From ae25dc842c4131b9836fe5d7f697c439a429d78a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Fri, 14 Feb 2020 12:00:09 +0100 Subject: [PATCH 1/3] chore(e2e): Refactor e2e to better track errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Collect results from various `kn` calls to provide the context * Changed sub-Run() commands to t.Log() to reduce the log noise and get file + line information in the log output * Removed any Fatal() calls to allows the test to properly finish * Only output via t.Log() to get the output at the proper places and allow Prow to better pick up the test results. * Most important: EMOJIS !! 🦆🦆🦆🦆🦆 --- go.mod | 4 +- go.sum | 23 +- test/e2e/basic_workflow_test.go | 183 +++++----- test/e2e/cli.go | 284 +++++++++++++++ test/e2e/common.go | 214 ++++-------- test/e2e/cronjob_test.go | 94 ++--- test/e2e/e2e.go | 40 --- test/e2e/env.go | 52 --- test/e2e/kn.go | 40 --- test/e2e/kubectl.go | 35 -- test/e2e/plugins_test.go | 252 +++++++------- test/e2e/revision_test.go | 167 +++++---- test/e2e/route_test.go | 87 +++-- test/e2e/service_options_test.go | 250 ++++++-------- test/e2e/service_test.go | 107 +++--- test/e2e/source_apiserver_test.go | 147 ++++---- test/e2e/source_binding_test.go | 73 ++-- test/e2e/source_list_types_test.go | 33 +- test/e2e/tekton_test.go | 46 +-- test/e2e/traffic_split_test.go | 325 ++++++++++-------- test/e2e/trigger_test.go | 119 +++---- test/e2e/version_test.go | 9 +- .../exporter/stackdriver/go.mod | 10 +- .../exporter/stackdriver/go.sum | 35 +- .../exporter/stackdriver/stackdriver.go | 5 + .../exporter/stackdriver/trace.go | 34 ++ vendor/modules.txt | 4 +- 27 files changed, 1382 insertions(+), 1290 deletions(-) create mode 100644 test/e2e/cli.go delete mode 100644 test/e2e/e2e.go delete mode 100644 test/e2e/env.go delete mode 100644 test/e2e/kn.go delete mode 100644 test/e2e/kubectl.go diff --git a/go.mod b/go.mod index d4f4b59ef4..09b20bed92 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module knative.dev/client require ( contrib.go.opencensus.io/exporter/ocagent v0.6.0 // indirect contrib.go.opencensus.io/exporter/prometheus v0.1.0 // indirect - contrib.go.opencensus.io/exporter/stackdriver v0.12.9 // indirect - github.com/google/go-containerregistry v0.0.0-20200131185320-aec8da010de2 // indirect + contrib.go.opencensus.io/exporter/stackdriver v0.13.0 // indirect + github.com/google/go-containerregistry v0.0.0-20200212224832-c629a66d7231 // indirect github.com/magiconair/properties v1.8.0 github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a // indirect github.com/mitchellh/go-homedir v1.1.0 diff --git a/go.sum b/go.sum index abc75ef5d7..e9cd91005a 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,8 @@ contrib.go.opencensus.io/exporter/ocagent v0.6.0 h1:Z1n6UAyr0QwM284yUuh5Zd8JlvxU contrib.go.opencensus.io/exporter/ocagent v0.6.0/go.mod h1:zmKjrJcdo0aYcVS7bmEeSEBLPA9YJp5bjrofdU3pIXs= contrib.go.opencensus.io/exporter/prometheus v0.1.0 h1:SByaIoWwNgMdPSgl5sMqM2KDE5H/ukPWBRo314xiDvg= contrib.go.opencensus.io/exporter/prometheus v0.1.0/go.mod h1:cGFniUXGZlKRjzOyuZJ6mgB+PgBcCIa79kEKR8YCW+A= -contrib.go.opencensus.io/exporter/stackdriver v0.12.9 h1:ZRVpDigsb+nVI/yps/NLDOYzYjFFmm3OCsBhmYocxR0= -contrib.go.opencensus.io/exporter/stackdriver v0.12.9/go.mod h1:XyyafDnFOsqoxHJgTFycKZMrRUrPThLh2iYTJF6uoO0= +contrib.go.opencensus.io/exporter/stackdriver v0.13.0 h1:Jaz7WbqjtfoCPa1KbfisCX+P5aM3DizEY9pQMU0oAQo= +contrib.go.opencensus.io/exporter/stackdriver v0.13.0/go.mod h1:z2tyTZtPmQ2HvWH4cOmVDgtY+1lomfKdbLnkJvZdc8c= github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= @@ -118,12 +118,10 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0= -github.com/go-openapi/jsonpointer v0.19.2 h1:A9+F4Dc/MCNB5jibxf6rRvOvR/iFgQdyNx9eIhnGqq0= github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg= github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg= -github.com/go-openapi/jsonreference v0.19.2 h1:o20suLFB4Ri0tuzpWtyHlh7E7HnkqTNLq6aR6WVNS1w= github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc= github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o= github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8= @@ -131,7 +129,6 @@ github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nA github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc= github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo= github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I= -github.com/go-openapi/swag v0.19.2 h1:jvO6bCMBEilGwMfHhrd61zIID4oIFdwb76V17SM88dE= github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= @@ -154,7 +151,6 @@ github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -167,8 +163,8 @@ github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-containerregistry v0.0.0-20200131185320-aec8da010de2 h1:/z0FoA29APs30PljxT6GoZQekF5c1cYhow2osFsj1XU= -github.com/google/go-containerregistry v0.0.0-20200131185320-aec8da010de2/go.mod h1:Wtl/v6YdQxv397EREtzwgd9+Ud7Q5D8XMbi3Zazgkrs= +github.com/google/go-containerregistry v0.0.0-20200212224832-c629a66d7231 h1:zoj6E1dzY9aeZw1CGJv1hffxgyunrLpjI0SZWK7ynzg= +github.com/google/go-containerregistry v0.0.0-20200212224832-c629a66d7231/go.mod h1:Wtl/v6YdQxv397EREtzwgd9+Ud7Q5D8XMbi3Zazgkrs= github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= @@ -220,7 +216,6 @@ github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52Cu github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= @@ -244,7 +239,6 @@ github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0Q github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63 h1:nTT4s92Dgz2HlrB2NaMgvlfqHH39OgMhA7z3PK7PGD4= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.7.0 h1:aizVhC/NAAcKWb+5QsU1iNOZb4Yws5UO2I+aIprQITM= @@ -278,13 +272,11 @@ github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:v github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo= github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME= github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= @@ -362,7 +354,6 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -433,7 +424,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9 h1:rjwSpXsdiK0dV8/Naq3kAw9ymfAeJIyd0upUIElB+lI= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -462,13 +453,12 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f h1:25KHgbfyiSm6vwQLbM3zZIe1v9p/3ea4Rz+nnM5K/i4= golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -499,6 +489,7 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200115165105-de0b1760071a h1:bEJ3JL2YUH3tt9KX9dsy0WUF3WOrhjtNjK93o0svepY= golang.org/x/tools v0.0.0-20200115165105-de0b1760071a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= diff --git a/test/e2e/basic_workflow_test.go b/test/e2e/basic_workflow_test.go index 4ddefb3f64..a1b51f0fa3 100644 --- a/test/e2e/basic_workflow_test.go +++ b/test/e2e/basic_workflow_test.go @@ -22,109 +22,112 @@ import ( "testing" "gotest.tools/assert" + "knative.dev/client/pkg/util" ) func TestBasicWorkflow(t *testing.T) { t.Parallel() - test := NewE2eTest(t) - test.Setup(t) - defer test.Teardown(t) - - t.Run("returns no service before running tests", func(t *testing.T) { - test.serviceListEmpty(t) - }) - - t.Run("create hello service and return no error", func(t *testing.T) { - test.serviceCreate(t, "hello") - }) - - t.Run("return valid info about hello service", func(t *testing.T) { - test.serviceList(t, "hello") - test.serviceDescribe(t, "hello") - }) - - t.Run("update hello service's configuration and return no error", func(t *testing.T) { - test.serviceUpdate(t, "hello", []string{"--env", "TARGET=kn", "--port", "8888"}) - }) - - t.Run("create another service and return no error", func(t *testing.T) { - test.serviceCreate(t, "svc2") - }) - - t.Run("return a list of revisions associated with hello and svc2 services", func(t *testing.T) { - test.revisionListForService(t, "hello") - test.revisionListForService(t, "svc2") - }) - - t.Run("describe revision from hello service", func(t *testing.T) { - test.revisionDescribe(t, "hello") - }) - - t.Run("delete hello and svc2 services and return no error", func(t *testing.T) { - test.serviceDelete(t, "hello") - test.serviceDelete(t, "svc2") - }) - - t.Run("return no service after completing tests", func(t *testing.T) { - test.serviceListEmpty(t) - }) - t.Run("error out of wrong commands and subcommands", func(t *testing.T) { - test.wrongSubCommand(t) - test.wrongCommand(t) - }) -} - -func (test *e2eTest) serviceListEmpty(t *testing.T) { - out, err := test.kn.RunWithOpts([]string{"service", "list"}, runOpts{NoNamespace: false}) + test, err := NewE2eTest() assert.NilError(t, err) + defer func() { + assert.NilError(t, test.Teardown()) + }() - assert.Check(t, util.ContainsAll(out, "No services found.")) -} + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() -func (test *e2eTest) serviceCreate(t *testing.T, serviceName string) { - out, err := test.kn.RunWithOpts([]string{"service", "create", serviceName, - "--image", KnDefaultTestImage}, runOpts{NoNamespace: false}) - assert.NilError(t, err) + t.Log("returns no service before running tests") + test.serviceListEmpty(t, r) + + t.Log("create hello service and return no error") + test.serviceCreate(t, r, "hello") + + t.Log("return valid info about hello service") + test.serviceList(t, r, "hello") + test.serviceDescribe(t, r, "hello") + + t.Log("update hello service's configuration and return no error") + test.serviceUpdate(t, r, "hello", "--env", "TARGET=kn", "--port", "8888") - assert.Check(t, util.ContainsAllIgnoreCase(out, "service", serviceName, "creating", "namespace", test.kn.namespace, "ready")) + t.Log("create another service and return no error") + test.serviceCreate(t, r, "svc2") + + t.Log("return a list of revisions associated with hello and svc2 services") + test.revisionListForService(t, r, "hello") + test.revisionListForService(t, r, "svc2") + + t.Log("describe revision from hello service") + test.revisionDescribe(t, r, "hello") + + t.Log("delete hello and svc2 services and return no error") + test.serviceDelete(t, r, "hello") + test.serviceDelete(t, r, "svc2") + + t.Log("return no service after completing tests") + test.serviceListEmpty(t, r) } -func (test *e2eTest) serviceList(t *testing.T, serviceName string) { - out, err := test.kn.RunWithOpts([]string{"service", "list", serviceName}, runOpts{NoNamespace: false}) - assert.NilError(t, err) +func TestWrongCommand(t *testing.T) { + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + out := kn{}.Run("source", "apiserver", "noverb", "--tag=0.13") + assert.Check(t, util.ContainsAll(out.Stderr, "Error", "unknown subcommand", "noverb")) + r.AssertError(out) + + out = kn{}.Run("rev") + assert.Check(t, util.ContainsAll(out.Stderr, "Error", "unknown command", "rev")) + r.AssertError(out) - assert.Check(t, util.ContainsAll(out, serviceName)) } -func (test *e2eTest) serviceDescribe(t *testing.T, serviceName string) { - out, err := test.kn.RunWithOpts([]string{"service", "describe", serviceName}, runOpts{NoNamespace: false}) - assert.NilError(t, err) +// ========================================================================== - assert.Assert(t, util.ContainsAll(out, serviceName, test.kn.namespace, KnDefaultTestImage)) - assert.Assert(t, util.ContainsAll(out, "Conditions", "ConfigurationsReady", "Ready", "RoutesReady")) - assert.Assert(t, util.ContainsAll(out, "Name", "Namespace", "URL", "Age", "Revisions")) +func (test *e2eTest) serviceListEmpty(t *testing.T, r *KnRunResultCollector) { + out := test.kn.Run("service", "list") + r.AssertNoError(out) + assert.Check(t, util.ContainsAll(out.Stdout, "No services found.")) } -func (test *e2eTest) serviceUpdate(t *testing.T, serviceName string, args []string) { - out, err := test.kn.RunWithOpts(append([]string{"service", "update", serviceName}, args...), runOpts{NoNamespace: false}) - assert.NilError(t, err) +func (test *e2eTest) serviceCreate(t *testing.T, r *KnRunResultCollector, serviceName string) { + out := test.kn.Run("service", "create", serviceName, "--image", KnDefaultTestImage) + r.AssertNoError(out) + assert.Check(t, util.ContainsAllIgnoreCase(out.Stdout, "service", serviceName, "creating", "namespace", test.kn.namespace, "ready")) +} - assert.Check(t, util.ContainsAllIgnoreCase(out, "updating", "service", serviceName, "ready")) +func (test *e2eTest) serviceList(t *testing.T, r *KnRunResultCollector, serviceName string) { + out := test.kn.Run("service", "list", serviceName) + r.AssertNoError(out) + assert.Check(t, util.ContainsAll(out.Stdout, serviceName)) } -func (test *e2eTest) serviceDelete(t *testing.T, serviceName string) { - out, err := test.kn.RunWithOpts([]string{"service", "delete", serviceName}, runOpts{NoNamespace: false}) - assert.NilError(t, err) +func (test *e2eTest) serviceDescribe(t *testing.T, r *KnRunResultCollector, serviceName string) { + out := test.kn.Run("service", "describe", serviceName) + r.AssertNoError(out) + assert.Assert(t, util.ContainsAll(out.Stdout, serviceName, test.kn.namespace, KnDefaultTestImage)) + assert.Assert(t, util.ContainsAll(out.Stdout, "Conditions", "ConfigurationsReady", "Ready", "RoutesReady")) + assert.Assert(t, util.ContainsAll(out.Stdout, "Name", "Namespace", "URL", "Age", "Revisions")) +} - assert.Check(t, util.ContainsAll(out, "Service", serviceName, "successfully deleted in namespace", test.kn.namespace)) +func (test *e2eTest) serviceUpdate(t *testing.T, r *KnRunResultCollector, serviceName string, args ...string) { + fullArgs := append([]string{}, "service", "update", serviceName) + fullArgs = append(fullArgs, args...) + out := test.kn.Run(fullArgs...) + r.AssertNoError(out) + assert.Check(t, util.ContainsAllIgnoreCase(out.Stdout, "updating", "service", serviceName, "ready")) } -func (test *e2eTest) revisionListForService(t *testing.T, serviceName string) { - out, err := test.kn.RunWithOpts([]string{"revision", "list", "-s", serviceName}, runOpts{NoNamespace: false}) - assert.NilError(t, err) +func (test *e2eTest) serviceDelete(t *testing.T, r *KnRunResultCollector, serviceName string) { + out := test.kn.Run("service", "delete", serviceName) + r.AssertNoError(out) + assert.Check(t, util.ContainsAll(out.Stdout, "Service", serviceName, "successfully deleted in namespace", test.kn.namespace)) +} - outputLines := strings.Split(out, "\n") +func (test *e2eTest) revisionListForService(t *testing.T, r *KnRunResultCollector, serviceName string) { + out := test.kn.Run("revision", "list", "-s", serviceName) + r.AssertNoError(out) + outputLines := strings.Split(out.Stdout, "\n") // Ignore the last line because it is an empty string caused by splitting a line break // at the end of the output string for _, line := range outputLines[1 : len(outputLines)-1] { @@ -133,22 +136,10 @@ func (test *e2eTest) revisionListForService(t *testing.T, serviceName string) { } } -func (test *e2eTest) revisionDescribe(t *testing.T, serviceName string) { - revName := test.findRevision(t, serviceName) - - out, err := test.kn.RunWithOpts([]string{"revision", "describe", revName}, runOpts{}) - assert.NilError(t, err) - assert.Check(t, util.ContainsAll(out, revName, test.kn.namespace, serviceName, "++ Ready", "TARGET=kn")) -} - -func (test *e2eTest) wrongSubCommand(t *testing.T) { - - _, err := test.kn.RunWithOpts([]string{"source", "apiserver", "noverb", "--tag=0.13"}, runOpts{AllowError: true}) - assert.ErrorContains(t, err, "Error: unknown subcommand 'noverb' for 'kn source apiserver'. Available subcommands: create, delete, describe, list, update") -} - -func (test *e2eTest) wrongCommand(t *testing.T) { +func (test *e2eTest) revisionDescribe(t *testing.T, r *KnRunResultCollector, serviceName string) { + revName := test.findRevision(t, r, serviceName) - _, err := test.kn.RunWithOpts([]string{"rev"}, runOpts{AllowError: true}) - assert.ErrorContains(t, err, "Error: unknown command 'rev'", "Run 'kn --help' for usage.") + out := test.kn.Run("revision", "describe", revName) + r.AssertNoError(out) + assert.Check(t, util.ContainsAll(out.Stdout, revName, test.kn.namespace, serviceName, "++ Ready", "TARGET=kn")) } diff --git a/test/e2e/cli.go b/test/e2e/cli.go new file mode 100644 index 0000000000..e3833e1eb7 --- /dev/null +++ b/test/e2e/cli.go @@ -0,0 +1,284 @@ +// Copyright 2020 The Knative Authors + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package e2e + +import ( + "bytes" + "fmt" + "io" + "os/exec" + "strings" + "testing" + + "github.com/pkg/errors" +) + +type kn struct { + namespace string +} + +const ( + seperatorHeavy = "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + seperatorLight = "╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍" +) + +// Run the 'kn' CLI with args and opts +func (k kn) Run(args ...string) KnRunResult { + return RunKn(k.namespace, args) +} + +// Helper methods for calling out to the test cluster +type kubectl struct { + namespace string +} + +// Run the 'kubectl' CLI with args and opts +func (k kubectl) Run(args ...string) (string, error) { + return RunKubectl(k.namespace, args...) +} + +// Collector for results +type KnRunResultCollector struct { + results []KnRunResult + extraDumps []string + t *testing.T +} + +func NewKnRunResultCollector(t *testing.T) *KnRunResultCollector { + return &KnRunResultCollector{ + results: []KnRunResult{}, + t: t, + extraDumps: []string{}, + } +} + +func (c *KnRunResultCollector) AssertNoError(result KnRunResult) { + c.results = append(c.results, result) + if result.Error != nil { + c.t.Logf("ERROR: %v", result.Stderr) + c.t.FailNow() + } +} + +func (c *KnRunResultCollector) AssertError(result KnRunResult) { + c.results = append(c.results, result) + if result.Error == nil { + c.t.Log("ERROR: Error expected but no error happened") + c.t.FailNow() + } +} + +// AddDump adds extra dump information to the collector which is printed +// out if an error occurs +func (c *KnRunResultCollector) AddDump(kind string, name string, namespace string) { + dumpInfo := extractDumpInfo(kind, name, namespace) + if dumpInfo != "" { + c.extraDumps = append(c.extraDumps, dumpInfo) + } +} + +func (c *KnRunResultCollector) DumpIfFailed() { + if c.t.Failed() { + c.t.Log(c.errorDetails()) + } +} + +func (c *KnRunResultCollector) errorDetails() string { + var out = bytes.Buffer{} + fmt.Fprintln(&out, "=== FAIL: =======================[[ERROR]]========================") + c.printCommands(&out) + var dumpInfos []string + if len(c.results) > 0 { + dumpInfo := c.results[len(c.results)-1].DumpInfo + if dumpInfo != "" { + dumpInfos = append(dumpInfos, dumpInfo) + } + } + dumpInfos = append(dumpInfos, c.extraDumps...) + for _, d := range dumpInfos { + fmt.Fprintln(&out, "--------------------------[[DUMP]]-------------------------------") + fmt.Fprintf(&out, d) + } + + fmt.Fprintln(&out, "=================================================================") + return out.String() +} + +func (c *KnRunResultCollector) printCommands(out io.Writer) { + for i, result := range c.results { + c.printCommand(out, result) + if i < len(c.results)-1 { + fmt.Fprintf(out, "┣━%s\n", seperatorHeavy) + } + } +} + +func (c *KnRunResultCollector) printCommand(out io.Writer, result KnRunResult) { + fmt.Fprintf(out, "🦆 %s\n", result.CmdLine) + for _, l := range strings.Split(result.Stdout, "\n") { + fmt.Fprintf(out, "┃ %s\n", l) + } + if result.Stderr != "" { + errorPrefix := "🔥" + if result.ErrorExpected { + errorPrefix = "︙" + } + for _, l := range strings.Split(result.Stderr, "\n") { + fmt.Fprintf(out, "%s %s\n", errorPrefix, l) + } + } +} + +// ======================================================== +// Functions: + +// Result of a "kn" call +type KnRunResult struct { + // Command line called + CmdLine string + // Standard output of command + Stdout string + // Standard error of command + Stderr string + // And extra dump informations in case of an unexpected error + DumpInfo string + // Error occurred during execution + Error error + // Was an error expected ? + ErrorExpected bool +} + +// RunKubectl runs "kk" in a given namespace +func RunKn(namespace string, args []string) KnRunResult { + if namespace != "" { + args = append(args, "--namespace", namespace) + } + stdout, stderr, err := runCli("kn", args) + result := KnRunResult{ + CmdLine: cmdCLIDesc("kn", args), + Stdout: stdout, + Stderr: stderr, + Error: err, + } + if err != nil { + command := args[0] + var name string + if len(args) > 2 { + name = args[2] + } + result.DumpInfo = extractDumpInfo(command, name, namespace) + } + return result +} + +// RunKubectl runs "kubectl" in a given namespace +func RunKubectl(namespace string, args ...string) (string, error) { + if namespace != "" { + args = append(args, "--namespace", namespace) + } + stdout, stderr, err := runCli("kubectl", args) + if err != nil { + return stdout, errors.Wrap(err, fmt.Sprintf("stderr: %s", stderr)) + } + return stdout, nil +} + +func runCli(cli string, args []string) (string, string, error) { + var stderr bytes.Buffer + var stdout bytes.Buffer + + cmd := exec.Command(cli, args...) + cmd.Stderr = &stderr + cmd.Stdout = &stdout + cmd.Stdin = nil + + err := cmd.Run() + return stdout.String(), stderr.String(), err +} + +type dumpFunc func(name string, namespace string) string + +// Dump handler for specific commands ("service", "revision") which should add extra infos +// Relies on that argv[1] is the command and argv[3] is the name of the object +var dumpHandlers = map[string]dumpFunc{ + "service": dumpService, +} + +func extractDumpInfo(command, name string, namespace string) string { + dumpHandler := dumpHandlers[command] + if dumpHandler != nil { + return dumpHandler(name, namespace) + } + return "" +} + +func dumpService(name, namespace string) string { + // For list like operation we don't have a name + if name == "" { + return "" + } + var buffer bytes.Buffer + + // Service info + appendResourceInfo(&buffer, "ksvc", name, namespace) + fmt.Fprintf(&buffer, "%s\n", seperatorHeavy) + // Service's configuration + appendResourceInfo(&buffer, "configuration", name, namespace) + fmt.Fprintf(&buffer, "%s\n", seperatorHeavy) + // Get all revisions for this service + appendResourceInfoWithNameSelector(&buffer, "revision", name, namespace, "serving.knative.dev/service") + // Get all routes for this service + appendResourceInfoWithNameSelector(&buffer, "route", name, namespace, "serving.knative.dev/service") + return buffer.String() +} + +func appendResourceInfo(buffer *bytes.Buffer, kind string, name string, namespace string) { + appendResourceInfoWithNameSelector(buffer, kind, name, namespace, "") +} + +func appendResourceInfoWithNameSelector(buffer *bytes.Buffer, kind string, name string, namespace string, selector string) { + var extra string + argsDescribe := []string{"describe", kind} + argsGet := []string{"get", "-oyaml", kind} + + if selector != "" { + labelArg := fmt.Sprintf("%s=%s", selector, name) + argsDescribe = append(argsDescribe, "--selector", labelArg) + argsGet = append(argsGet, "--selector", labelArg) + extra = fmt.Sprintf(" --selector %s", labelArg) + } else { + argsDescribe = append(argsDescribe, name) + argsGet = append(argsGet, name) + extra = "" + } + + out, err := RunKubectl(namespace, argsDescribe...) + appendCLIOutput(buffer, fmt.Sprintf("kubectl describe %s %s --namespace %s%s", kind, name, namespace, extra), out, err) + fmt.Fprintf(buffer, "%s\n", seperatorLight) + out, err = RunKubectl(namespace, argsGet...) + appendCLIOutput(buffer, fmt.Sprintf("kubectl get %s %s --namespace %s -oyaml%s", kind, name, namespace, extra), out, err) +} + +func appendCLIOutput(buffer *bytes.Buffer, desc string, out string, err error) { + buffer.WriteString(fmt.Sprintf("\n==== %s\n", desc)) + if err != nil { + buffer.WriteString(fmt.Sprintf("%s: %v\n", "!!!! ERROR", err)) + } + buffer.WriteString(out) +} + +func cmdCLIDesc(cli string, args []string) string { + return fmt.Sprintf("%s %s", cli, strings.Join(args, " ")) +} diff --git a/test/e2e/common.go b/test/e2e/common.go index bdd322a469..2d954fdc09 100644 --- a/test/e2e/common.go +++ b/test/e2e/common.go @@ -15,28 +15,17 @@ package e2e import ( - "bytes" "fmt" - "io" "os" - "os/exec" "regexp" "strconv" "strings" "sync" "testing" "time" -) -type runOpts struct { - NoNamespace bool - AllowError bool - StderrWriter io.Writer - StdoutWriter io.Writer - StdinReader io.Reader - CancelCh chan struct{} - Redact bool -} + "github.com/pkg/errors" +) const ( KnDefaultTestImage string = "gcr.io/knative-samples/helloworld-go" @@ -44,114 +33,124 @@ const ( RetrySleepDuration time.Duration = 5 * time.Second ) -var m sync.Mutex +var nsMutex sync.Mutex +var serviceMutex sync.Mutex +var serviceCount int +var namespaceCount int type e2eTest struct { - env env - kn kn - createNamespaceOnSetup bool - namespaceCreated bool + namespace string + kn kn } -func NewE2eTest(t *testing.T) *e2eTest { - return &e2eTest{ - env: buildEnv(t), - createNamespaceOnSetup: true, +func NewE2eTest() (*e2eTest, error) { + ns := nextNamespace() + + err := createNamespace(ns) + if err != nil { + return nil, err + } + err = waitForNamespaceCreated(ns) + if err != nil { + return nil, err } + + return &e2eTest{ + namespace: ns, + kn: kn{ns}, + }, nil } -// Setup set up an environment for kn integration test returns the Teardown cleanup function -func (test *e2eTest) Setup(t *testing.T) { - test.env.Namespace = fmt.Sprintf("%s%d", test.env.Namespace, getNamespaceCountAndIncrement()) - test.kn = kn{t, test.env.Namespace, Logger{}} - if test.createNamespaceOnSetup { - test.CreateTestNamespace(t, test.env.Namespace) - test.WaitForNamespaceCreated(t, test.env.Namespace) +func nextNamespace() string { + ns := os.Getenv("KN_E2E_NAMESPACE") + if ns == "" { + ns = "kne2etests" } + return fmt.Sprintf("%s%d", ns, getNextNamespaceId()) } -func getNamespaceCountAndIncrement() int { - m.Lock() - defer m.Unlock() +func getNextNamespaceId() int { + nsMutex.Lock() + defer nsMutex.Unlock() current := namespaceCount namespaceCount++ return current } -func getServiceNameAndIncrement(base string) string { - m.Lock() - defer m.Unlock() +func getNextServiceName(base string) string { + serviceMutex.Lock() + defer serviceMutex.Unlock() current := serviceCount serviceCount++ return base + strconv.Itoa(current) } // Teardown clean up -func (test *e2eTest) Teardown(t *testing.T) { - if test.namespaceCreated { - test.DeleteTestNamespace(t, test.env.Namespace) - } +func (test *e2eTest) Teardown() error { + return deleteNamespace(test.namespace) } -// CreateTestNamespace creates and tests a namesspace creation invoking kubectl -func (test *e2eTest) CreateTestNamespace(t *testing.T, namespace string) { - logger := Logger{} +// createNamespace creates and tests a namesspace creation invoking kubectl +func createNamespace(namespace string) error { expectedOutputRegexp := fmt.Sprintf("namespace?.+%s.+created", namespace) - out, err := createNamespace(t, namespace, MaxRetries, logger) + out, err := createNamespaceWithRetry(namespace, MaxRetries) if err != nil { - logger.Fatalf("Could not create namespace with error %v, giving up\n", err) + return errors.Wrap(err, "could not create namespace "+namespace) } // check that last output indeed show created namespace - if !matchRegexp(t, expectedOutputRegexp, out) { - t.Fatalf("Expected output incorrect, expecting to include:\n%s\n Instead found:\n%s\n", expectedOutputRegexp, out) + matched, err := matchRegexp(expectedOutputRegexp, out) + if err != nil { + return err + } + if !matched { + return fmt.Errorf("Expected output incorrect, expecting to include:\n%s\n Instead found:\n%s\n", expectedOutputRegexp, out) } - test.namespaceCreated = true + return nil } -// CreateTestNamespace deletes and tests a namesspace deletion invoking kubectl -func (test *e2eTest) DeleteTestNamespace(t *testing.T, namespace string) { - kubectl := kubectl{t, Logger{}} - out, err := kubectl.RunWithOpts([]string{"delete", "namespace", namespace}, runOpts{}) +// createNamespace deletes and tests a namesspace deletion invoking kubectl +func deleteNamespace(namespace string) error { + kubectl := kubectl{namespace} + out, err := kubectl.Run("delete", "namespace", namespace) if err != nil { - t.Fatalf("Error executing 'kubectl delete namespace' command. Error: %s", err.Error()) + return errors.Wrap(err, fmt.Sprintf("Cannot delete namespace %s", namespace)) } expectedOutputRegexp := fmt.Sprintf("namespace?.+%s.+deleted", namespace) - if !matchRegexp(t, expectedOutputRegexp, out) { - t.Fatalf("Expected output incorrect, expecting to include:\n%s\n Instead found:\n%s\n", expectedOutputRegexp, out) + matched, err := matchRegexp(expectedOutputRegexp, out) + if err != nil { + return err + } + if !matched { + return fmt.Errorf("Expected output incorrect, expecting to include:\n%s\n Instead found:\n%s\n", expectedOutputRegexp, out) } - test.namespaceCreated = false + return nil } // WaitForNamespaceDeleted wait until namespace is deleted -func (test *e2eTest) WaitForNamespaceDeleted(t *testing.T, namespace string) { - logger := Logger{} - deleted := checkNamespace(t, namespace, false, MaxRetries, logger) +func waitForNamespaceDeleted(namespace string) error { + deleted := checkNamespace(namespace, false, MaxRetries) if !deleted { - t.Fatalf("Error deleting namespace %s, timed out", namespace) + return fmt.Errorf("error deleting namespace %s, timed out after %d retries", namespace, MaxRetries) } + return nil } // WaitForNamespaceCreated wait until namespace is created -func (test *e2eTest) WaitForNamespaceCreated(t *testing.T, namespace string) { - logger := Logger{} - created := checkNamespace(t, namespace, true, MaxRetries, logger) +func waitForNamespaceCreated(namespace string) error { + created := checkNamespace(namespace, true, MaxRetries) if !created { - t.Fatalf("Error creating namespace %s, timed out", namespace) + return fmt.Errorf("error creating namespace %s, timed out after %d retries", namespace, MaxRetries) } + return nil } // Private functions -func checkNamespace(t *testing.T, namespace string, created bool, maxRetries int, logger Logger) bool { - kubectlGetNamespace := func() (string, error) { - kubectl := kubectl{t, logger} - return kubectl.RunWithOpts([]string{"get", "namespace"}, runOpts{}) - } - +func checkNamespace(namespace string, created bool, maxRetries int) bool { retries := 0 for retries < MaxRetries { - output, _ := kubectlGetNamespace() + output, _ := kubectl{}.Run("get", "namespace") // check for namespace deleted if !created && !strings.Contains(output, namespace) { @@ -164,19 +163,13 @@ func checkNamespace(t *testing.T, namespace string, created bool, maxRetries int } retries++ - logger.Debugf("Namespace is terminating, waiting %ds, and trying again: %d of %d\n", int(RetrySleepDuration.Seconds()), retries, maxRetries) time.Sleep(RetrySleepDuration) } return true } -func createNamespace(t *testing.T, namespace string, maxRetries int, logger Logger) (string, error) { - kubectlCreateNamespace := func() (string, error) { - kubectl := kubectl{t, logger} - return kubectl.RunWithOpts([]string{"create", "namespace", namespace}, runOpts{AllowError: true}) - } - +func createNamespaceWithRetry(namespace string, maxRetries int) (string, error) { var ( retries int err error @@ -184,82 +177,23 @@ func createNamespace(t *testing.T, namespace string, maxRetries int, logger Logg ) for retries < maxRetries { - out, err = kubectlCreateNamespace() + out, err = kubectl{}.Run("create", "namespace", namespace) if err == nil { return out, nil } retries++ - logger.Debugf("Could not create namespace with error %v, waiting %ds, and trying again: %d of %d\n", err, int(RetrySleepDuration.Seconds()), retries, maxRetries) time.Sleep(RetrySleepDuration) } return out, err } -func runCLIWithOpts(cli string, args []string, opts runOpts, logger Logger) (string, error) { - logger.Debugf("Running '%s'...\n", cmdCLIDesc(cli, args)) - - var stderr bytes.Buffer - var stdout bytes.Buffer - - cmd := exec.Command(cli, args...) - cmd.Stderr = &stderr - - if opts.CancelCh != nil { - go func() { - select { - case <-opts.CancelCh: - cmd.Process.Signal(os.Interrupt) - } - }() - } - - if opts.StdoutWriter != nil { - cmd.Stdout = opts.StdoutWriter - } else { - cmd.Stdout = &stdout - } - - cmd.Stdin = opts.StdinReader - - err := cmd.Run() - if err != nil { - err = fmt.Errorf("Execution error: stderr: '%s' error: '%s'", stderr.String(), err) - if !opts.AllowError { - fmt.Println("================[[Error]]=================") - fmt.Println(stdout.String()) - dumpKsvc(args, logger) - logger.Fatalf("Failed to successfully execute '%s': %v", cmdCLIDesc(cli, args), err) - } - } - - return stdout.String(), err -} - -func dumpKsvc(args []string, logger Logger) { - if args[0] == "service" { - opts := runOpts{AllowError: true} - ns := args[len(args)-1] - out, err := runCLIWithOpts("kubectl", []string{"-n", ns, "describe", "ksvc", args[2]}, opts, logger) - fmt.Println(err) - fmt.Println(out) - out, err = runCLIWithOpts("kubectl", []string{"-n", ns, "get", "ksvc", args[2], "-oyaml"}, opts, logger) - fmt.Println(err) - fmt.Println(out) - fmt.Println("================[[Error]]=================") - } -} - -func cmdCLIDesc(cli string, args []string) string { - return fmt.Sprintf("%s %s", cli, strings.Join(args, " ")) -} - -func matchRegexp(t *testing.T, matchingRegexp, actual string) bool { +func matchRegexp(matchingRegexp, actual string) (bool, error) { matched, err := regexp.MatchString(matchingRegexp, actual) if err != nil { - t.Fatalf("Failed to match regexp '%s'. Error: '%s'", matchingRegexp, err.Error()) + return false, errors.Wrap(err, fmt.Sprintf("failed to match regexp '%s'", matchingRegexp)) } - return matched + return matched, nil } func currentDir(t *testing.T) string { diff --git a/test/e2e/cronjob_test.go b/test/e2e/cronjob_test.go index cbfd6a38c6..94d04cf92b 100644 --- a/test/e2e/cronjob_test.go +++ b/test/e2e/cronjob_test.go @@ -21,61 +21,67 @@ import ( "testing" "gotest.tools/assert" + "knative.dev/client/pkg/util" ) func TestSourceCronJob(t *testing.T) { t.Parallel() - test := NewE2eTest(t) - test.Setup(t) - defer test.Teardown(t) - - test.serviceCreate(t, "testsvc0") - - t.Run("create cronJob sources with a sink to a service", func(t *testing.T) { - test.cronJobSourceCreate(t, "testcronjobsource0", "* * * * */1", "ping", "svc:testsvc0") - }) - - t.Run("delete cronJob sources", func(t *testing.T) { - test.cronJobSourceDelete(t, "testcronjobsource0") - }) - - t.Run("create cronJob source with a missing sink service", func(t *testing.T) { - test.cronJobSourceCreateMissingSink(t, "testcronjobsource1", "* * * * */1", "ping", "svc:unknown") - }) - - t.Run("update cronJob source sink service", func(t *testing.T) { - test.cronJobSourceCreate(t, "testcronjobsource2", "* * * * */1", "ping", "svc:testsvc0") - test.serviceCreate(t, "testsvc1") - test.cronJobSourceUpdateSink(t, "testcronjobsource2", "svc:testsvc1") - jpSinkRefNameInSpec := "jsonpath={.spec.sink.ref.name}" - out, err := test.getResourceFieldsWithJSONPath(t, "cronjobsource", "testcronjobsource2", jpSinkRefNameInSpec) - assert.NilError(t, err) - assert.Equal(t, out, "testsvc1") - }) -} + test, err := NewE2eTest() + assert.NilError(t, err) + defer func() { + assert.NilError(t, test.Teardown()) + }() + + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + t.Log("Creating a testservice") + test.serviceCreate(t, r, "testsvc0") + + t.Log("create cronJob sources with a sink to a service") + + test.cronJobSourceCreate(t, r, "testcronjobsource0", "* * * * */1", "ping", "svc:testsvc0") -func (test *e2eTest) cronJobSourceCreate(t *testing.T, sourceName string, schedule string, data string, sink string) { - out, err := test.kn.RunWithOpts([]string{"source", "cronjob", "create", sourceName, - "--schedule", schedule, "--data", data, "--sink", sink}, runOpts{NoNamespace: false}) + t.Log("delete cronJob sources") + test.cronJobSourceDelete(t, r, "testcronjobsource0") + + t.Log("create cronJob source with a missing sink service") + test.cronJobSourceCreateMissingSink(t, r, "testcronjobsource1", "* * * * */1", "ping", "svc:unknown") + + t.Log("update cronJob source sink service") + test.cronJobSourceCreate(t, r, "testcronjobsource2", "* * * * */1", "ping", "svc:testsvc0") + test.serviceCreate(t, r, "testsvc1") + test.cronJobSourceUpdateSink(t, r, "testcronjobsource2", "svc:testsvc1") + jpSinkRefNameInSpec := "jsonpath={.spec.sink.ref.name}" + out, err := test.getResourceFieldsWithJSONPath("cronjobsource", "testcronjobsource2", jpSinkRefNameInSpec) assert.NilError(t, err) - assert.Check(t, util.ContainsAllIgnoreCase(out, "cronjob", "source", sourceName, "created", "namespace", test.kn.namespace)) + assert.Equal(t, out, "testsvc1") } -func (test *e2eTest) cronJobSourceDelete(t *testing.T, sourceName string) { - out, err := test.kn.RunWithOpts([]string{"source", "cronjob", "delete", sourceName}, runOpts{NoNamespace: false}) - assert.NilError(t, err) - assert.Check(t, util.ContainsAllIgnoreCase(out, "cronjob", "source", sourceName, "deleted", "namespace", test.kn.namespace)) +func (test *e2eTest) cronJobSourceCreate(t *testing.T, r *KnRunResultCollector, sourceName string, schedule string, data string, sink string) { + out := test.kn.Run("source", "cronjob", "create", sourceName, + "--schedule", schedule, "--data", data, "--sink", sink) + assert.Check(t, util.ContainsAllIgnoreCase(out.Stdout, "cronjob", "source", sourceName, "created", "namespace", test.kn.namespace)) + r.AssertNoError(out) } -func (test *e2eTest) cronJobSourceCreateMissingSink(t *testing.T, sourceName string, schedule string, data string, sink string) { - _, err := test.kn.RunWithOpts([]string{"source", "cronjob", "create", sourceName, - "--schedule", schedule, "--data", data, "--sink", sink}, runOpts{NoNamespace: false, AllowError: true}) - assert.ErrorContains(t, err, "services.serving.knative.dev", "not found") +func (test *e2eTest) cronJobSourceDelete(t *testing.T, r *KnRunResultCollector, sourceName string) { + out := test.kn.Run("source", "cronjob", "delete", sourceName) + assert.Check(t, util.ContainsAllIgnoreCase(out.Stdout, "cronjob", "source", sourceName, "deleted", "namespace", test.kn.namespace)) + r.AssertNoError(out) + } -func (test *e2eTest) cronJobSourceUpdateSink(t *testing.T, sourceName string, sink string) { - out, err := test.kn.RunWithOpts([]string{"source", "cronjob", "update", sourceName, "--sink", sink}, runOpts{}) - assert.NilError(t, err) - assert.Check(t, util.ContainsAll(out, sourceName, "updated", "namespace", test.kn.namespace)) +func (test *e2eTest) cronJobSourceCreateMissingSink(t *testing.T, r *KnRunResultCollector, sourceName string, schedule string, data string, sink string) { + out := test.kn.Run("source", "cronjob", "create", sourceName, + "--schedule", schedule, "--data", data, "--sink", sink) + assert.Check(t, util.ContainsAll(out.Stderr, "services.serving.knative.dev", "not found")) + r.AssertError(out) +} + +func (test *e2eTest) cronJobSourceUpdateSink(t *testing.T, r *KnRunResultCollector, sourceName string, sink string) { + out := test.kn.Run("source", "cronjob", "update", sourceName, "--sink", sink) + assert.Check(t, util.ContainsAll(out.Stdout, sourceName, "updated", "namespace", test.kn.namespace)) + r.AssertNoError(out) } diff --git a/test/e2e/e2e.go b/test/e2e/e2e.go deleted file mode 100644 index 2e3566f99e..0000000000 --- a/test/e2e/e2e.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2019 The Knative Authors - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package e2e - -import ( - "fmt" - "os" -) - -// Logger default implementation -type Logger struct{} - -// Section prints a message -func (l Logger) Section(msg string, f func()) { - fmt.Printf("==> %s\n", msg) - f() -} - -// Debugf prints a debug message -func (l Logger) Debugf(msg string, args ...interface{}) { - fmt.Printf(msg, args...) -} - -// Fatalf prints a fatal message -func (l Logger) Fatalf(msg string, args ...interface{}) { - fmt.Printf(msg, args...) - os.Exit(1) -} diff --git a/test/e2e/env.go b/test/e2e/env.go deleted file mode 100644 index 5bf95a087f..0000000000 --- a/test/e2e/env.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2019 The Knative Authors - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package e2e - -import ( - "os" - "strings" - "testing" -) - -type env struct { - Namespace string -} - -const defaultKnE2ENamespace = "kne2etests" - -var ( - namespaceCount = 0 - serviceCount = 0 -) - -func buildEnv(t *testing.T) env { - env := env{ - Namespace: os.Getenv("KN_E2E_NAMESPACE"), - } - env.validate(t) - return env -} - -func (e *env) validate(t *testing.T) { - errStrs := []string{} - - if e.Namespace == "" { - e.Namespace = defaultKnE2ENamespace - } - - if len(errStrs) > 0 { - t.Fatalf("%s", strings.Join(errStrs, "\n")) - } -} diff --git a/test/e2e/kn.go b/test/e2e/kn.go deleted file mode 100644 index cdccf0e4a9..0000000000 --- a/test/e2e/kn.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2019 The knative Authors - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package e2e - -import ( - "testing" -) - -type kn struct { - t *testing.T - namespace string - l Logger -} - -// Run the 'kn' CLI with args -func (k kn) Run(args []string) string { - out, _ := k.RunWithOpts(args, runOpts{}) - return out -} - -// Run the 'kn' CLI with args and opts -func (k kn) RunWithOpts(args []string, opts runOpts) (string, error) { - if !opts.NoNamespace { - args = append(args, []string{"-n", k.namespace}...) - } - - return runCLIWithOpts("kn", args, opts, k.l) -} diff --git a/test/e2e/kubectl.go b/test/e2e/kubectl.go deleted file mode 100644 index b48d44d70e..0000000000 --- a/test/e2e/kubectl.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 The Knative Authors - -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at - -// http://www.apache.org/licenses/LICENSE-2.0 - -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package e2e - -import ( - "testing" -) - -type kubectl struct { - t *testing.T - l Logger -} - -// Run the 'kubectl' CLI with args -func (k kubectl) Run(args []string) string { - out, _ := k.RunWithOpts(args, runOpts{}) - return out -} - -// Run the 'kubectl' CLI with args and opts -func (k kubectl) RunWithOpts(args []string, opts runOpts) (string, error) { - return runCLIWithOpts("kubectl", args, opts, k.l) -} diff --git a/test/e2e/plugins_test.go b/test/e2e/plugins_test.go index d619fbaf8d..78f72dcc65 100644 --- a/test/e2e/plugins_test.go +++ b/test/e2e/plugins_test.go @@ -24,6 +24,7 @@ import ( "testing" "gotest.tools/assert" + "knative.dev/client/pkg/util" ) @@ -34,156 +35,159 @@ echo "Hello Knative, I'm a Kn plugin" echo " My plugin file is $0" echo " I received arguments: $1 $2 $3 $4"` - KnConfigDefault string = `plugins-dir: %s -lookup-plugins: %s` - - FileModeReadable = 0644 FileModeReadWrite = 0666 FileModeExecutable = 0777 ) -func TestPluginWorkflow(t *testing.T) { - var ( - knConfigDir, knPluginsDir, knPluginsDir2 string - knConfigPath, knPluginPath, knPluginPath2 string - lookupPlugins bool - err error - ) +type pluginTestConfig struct { + knConfigDir, knPluginsDir, knPluginsDir2 string + knConfigPath, knPluginPath, knPluginPath2 string +} + +func (pc *pluginTestConfig) setup() error { + var err error + pc.knConfigDir, err = ioutil.TempDir("", "kn-config") + if err != nil { + return err + } + + pc.knPluginsDir = filepath.Join(pc.knConfigDir, "plugins") + err = os.MkdirAll(pc.knPluginsDir, FileModeExecutable) + if err != nil { + return err + } + + pc.knPluginsDir2 = filepath.Join(pc.knConfigDir, "plugins2") + err = os.MkdirAll(pc.knPluginsDir2, FileModeExecutable) + if err != nil { + return err + } + pc.knConfigPath, err = createPluginFile("config.yaml", "", pc.knConfigDir, FileModeReadWrite) + if err != nil { + return err + } + + pc.knPluginPath, err = createPluginFile("kn-helloe2e", TestPluginCode, pc.knPluginsDir, FileModeExecutable) + if err != nil { + return err + } + pc.knPluginPath2, err = createPluginFile("kn-hello2e2e", TestPluginCode, pc.knPluginsDir2, FileModeExecutable) + if err != nil { + return err + } + return nil +} + +func (pc *pluginTestConfig) teardown() { + os.RemoveAll(pc.knConfigDir) +} + +func createPluginFile(fileName, fileContent, filePath string, fileMode os.FileMode) (string, error) { + file := filepath.Join(filePath, fileName) + err := ioutil.WriteFile(file, []byte(fileContent), fileMode) + return file, err +} + +func TestPluginWithoutLookup(t *testing.T) { t.Parallel() - test := NewE2eTest(t) - setup := func(t *testing.T) { - test.createNamespaceOnSetup = false - test.Setup(t) - defer test.Teardown(t) - knConfigDir, err = ioutil.TempDir("", "kn-config") - assert.NilError(t, err) + pc, oldPath := setupPluginTestConfigWithNewPath(t) + defer tearDownWithPath(pc, oldPath) - knPluginsDir = filepath.Join(knConfigDir, "plugins") - err = os.MkdirAll(knPluginsDir, FileModeExecutable) - assert.NilError(t, err) + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() - knPluginsDir2 = filepath.Join(knConfigDir, "plugins2") - err = os.MkdirAll(knPluginsDir2, FileModeExecutable) - assert.NilError(t, err) + knFlags := []string{fmt.Sprintf("--plugins-dir=%s", pc.knPluginsDir), "--lookup-plugins=false"} - knConfigPath = test.createFile(t, "config.yaml", "", knConfigDir, FileModeReadWrite) - assert.Assert(t, knConfigPath != "") + t.Log("list plugin in --plugins-dir") + listPlugin(t, r, knFlags, []string{pc.knPluginPath}, []string{}) - knPluginPath = test.createFile(t, "kn-helloe2e", TestPluginCode, knPluginsDir, FileModeExecutable) - assert.Assert(t, knPluginPath != "") + t.Log("execute plugin in --plugins-dir") + runPlugin(t, r, knFlags, "helloe2e", []string{"e2e", "test"}, []string{"Hello Knative, I'm a Kn plugin", "I received arguments: e2e"}) - knPluginPath2 = test.createFile(t, "kn-hello2e2e", TestPluginCode, knPluginsDir2, FileModeExecutable) - assert.Assert(t, knPluginPath2 != "") - } + t.Log("does not list any other plugin in $PATH") + listPlugin(t, r, knFlags, []string{pc.knPluginPath}, []string{pc.knPluginPath2}) - teardown := func(t *testing.T) { - err = os.RemoveAll(knConfigDir) - assert.NilError(t, err) - } + t.Log("with --lookup-plugins is true") +} + +func TestPluginWithLookup(t *testing.T) { + + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + pc := pluginTestConfig{} + assert.NilError(t, pc.setup()) + defer pc.teardown() + + knFlags := []string{fmt.Sprintf("--plugins-dir=%s", pc.knPluginsDir), "--lookup-plugins=true"} + + t.Log("list plugin in --plugins-dir") + listPlugin(t, r, knFlags, []string{pc.knPluginPath}, []string{pc.knPluginPath2}) - t.Run("when kn config is empty", func(t *testing.T) { - t.Run("when using --plugin-dir", func(t *testing.T) { - t.Run("when --plugins-dir has a plugin", func(t *testing.T) { - t.Run("when --lookup-plugins is false", func(t *testing.T) { - lookupPlugins = false - - setup(t) - defer teardown(t) - - assert.Assert(t, lookupPlugins == false) - knFlags := []string{fmt.Sprintf("--plugins-dir=%s", knPluginsDir), fmt.Sprintf("--lookup-plugins=%t", lookupPlugins)} - - t.Run("list plugin in --plugins-dir", func(t *testing.T) { - test.listPlugin(t, knFlags, []string{knPluginPath}, []string{}) - }) - - t.Run("execute plugin in --plugins-dir", func(t *testing.T) { - test.runPlugin(t, knFlags, "helloe2e", []string{"e2e", "test"}, []string{"Hello Knative, I'm a Kn plugin", "I received arguments: e2e"}) - }) - - t.Run("does not list any other plugin in $PATH", func(t *testing.T) { - test.listPlugin(t, knFlags, []string{knPluginPath}, []string{knPluginPath2}) - }) - }) - - t.Run("with --lookup-plugins is true", func(t *testing.T) { - lookupPlugins = true - - setup(t) - defer teardown(t) - - assert.Assert(t, lookupPlugins == true) - knFlags := []string{fmt.Sprintf("--plugins-dir=%s", knPluginsDir), fmt.Sprintf("--lookup-plugins=%t", lookupPlugins)} - - t.Run("list plugin in --plugins-dir", func(t *testing.T) { - test.listPlugin(t, knFlags, []string{knPluginPath}, []string{knPluginPath2}) - }) - - t.Run("execute plugin in --plugins-dir", func(t *testing.T) { - test.runPlugin(t, knFlags, "helloe2e", []string{}, []string{"Hello Knative, I'm a Kn plugin"}) - }) - - t.Run("when other plugins are in $PATH", func(t *testing.T) { - var oldPath string - - setupPath := func(t *testing.T) { - oldPath = os.Getenv("PATH") - err := os.Setenv("PATH", fmt.Sprintf("%s:%s", oldPath, knPluginsDir2)) - assert.NilError(t, err) - } - - tearDownPath := func(t *testing.T) { - err = os.Setenv("PATH", oldPath) - assert.NilError(t, err) - } - - t.Run("list plugin in $PATH", func(t *testing.T) { - setupPath(t) - defer tearDownPath(t) - test.listPlugin(t, knFlags, []string{knPluginPath, knPluginPath2}, []string{}) - }) - - t.Run("execute plugin in $PATH", func(t *testing.T) { - setupPath(t) - defer tearDownPath(t) - test.runPlugin(t, knFlags, "hello2e2e", []string{}, []string{"Hello Knative, I'm a Kn plugin"}) - }) - }) - }) - }) - }) - }) + t.Log("execute plugin in --plugins-dir") + runPlugin(t, r, knFlags, "helloe2e", []string{}, []string{"Hello Knative, I'm a Kn plugin"}) } -// Private +func TestListPluginInPath(t *testing.T) { -func (test *e2eTest) createFile(t *testing.T, fileName, fileContent, filePath string, fileMode os.FileMode) string { - file := filepath.Join(filePath, fileName) - err := ioutil.WriteFile(file, []byte(fileContent), fileMode) - assert.NilError(t, err) - return file + r := NewKnRunResultCollector(t) + + pc, oldPath := setupPluginTestConfigWithNewPath(t) + defer tearDownWithPath(pc, oldPath) + + t.Log("list plugin in $PATH") + knFlags := []string{fmt.Sprintf("--plugins-dir=%s", pc.knPluginsDir), "--lookup-plugins=true"} + listPlugin(t, r, knFlags, []string{pc.knPluginPath, pc.knPluginPath2}, []string{}) + + r.DumpIfFailed() } -func (test *e2eTest) listPlugin(t *testing.T, knFlags []string, expectedPlugins []string, unexpectedPlugins []string) { - knArgs := append([]string{}, knFlags...) - knArgs = append(knArgs, []string{"plugin", "list"}...) +func TestExecutePluginInPath(t *testing.T) { + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + pc, oldPath := setupPluginTestConfigWithNewPath(t) + defer tearDownWithPath(pc, oldPath) + + t.Log("execute plugin in $PATH") + knFlags := []string{fmt.Sprintf("--plugins-dir=%s", pc.knPluginsDir), "--lookup-plugins=true"} + runPlugin(t, r, knFlags, "hello2e2e", []string{}, []string{"Hello Knative, I'm a Kn plugin"}) +} + +func setupPluginTestConfigWithNewPath(t *testing.T) (pluginTestConfig, string) { + pc := pluginTestConfig{} + assert.NilError(t, pc.setup()) + oldPath := os.Getenv("PATH") + assert.NilError(t, os.Setenv("PATH", fmt.Sprintf("%s:%s", oldPath, pc.knPluginsDir2))) + return pc, oldPath +} + +func tearDownWithPath(pc pluginTestConfig, oldPath string) { + os.Setenv("PATH", oldPath) + pc.teardown() +} + +// Private + +func listPlugin(t *testing.T, r *KnRunResultCollector, knFlags []string, expectedPlugins []string, unexpectedPlugins []string) { + knArgs := append(knFlags, "plugin", "list") - out, err := test.kn.RunWithOpts(knArgs, runOpts{NoNamespace: true}) - assert.NilError(t, err) - assert.Check(t, util.ContainsAll(out, expectedPlugins...)) - assert.Check(t, util.ContainsNone(out, unexpectedPlugins...)) + out := kn{}.Run(knArgs...) + r.AssertNoError(out) + assert.Check(t, util.ContainsAll(out.Stdout, expectedPlugins...)) + assert.Check(t, util.ContainsNone(out.Stdout, unexpectedPlugins...)) } -func (test *e2eTest) runPlugin(t *testing.T, knFlags []string, pluginName string, args []string, expectedOutput []string) { +func runPlugin(t *testing.T, r *KnRunResultCollector, knFlags []string, pluginName string, args []string, expectedOutput []string) { knArgs := append([]string{}, knFlags...) knArgs = append(knArgs, pluginName) knArgs = append(knArgs, args...) - out, err := test.kn.RunWithOpts(knArgs, runOpts{NoNamespace: true}) - assert.NilError(t, err) + out := kn{}.Run(knArgs...) + r.AssertNoError(out) for _, output := range expectedOutput { - assert.Check(t, util.ContainsAll(out, output)) + assert.Check(t, util.ContainsAll(out.Stdout, output)) } } diff --git a/test/e2e/revision_test.go b/test/e2e/revision_test.go index ea765e5a7c..6d70006591 100644 --- a/test/e2e/revision_test.go +++ b/test/e2e/revision_test.go @@ -29,125 +29,118 @@ import ( func TestRevision(t *testing.T) { t.Parallel() - test := NewE2eTest(t) - test.Setup(t) - defer test.Teardown(t) - - t.Run("create hello service and return no error", func(t *testing.T) { - test.serviceCreate(t, "hello") - }) - - t.Run("describe revision from hello service with print flags", func(t *testing.T) { - revName := test.findRevision(t, "hello") - test.revisionDescribeWithPrintFlags(t, revName) - }) - - t.Run("update hello service and increase the count of configuration generation", func(t *testing.T) { - test.serviceUpdate(t, "hello", []string{"--env", "TARGET=kn", "--port", "8888"}) - }) - - t.Run("show a list of revisions sorted by the count of configuration generation", func(t *testing.T) { - test.revisionListWithService(t, "hello") - }) - - t.Run("delete latest revision from hello service and return no error", func(t *testing.T) { - revName := test.findRevision(t, "hello") - test.revisionDelete(t, revName) - }) - - t.Run("delete three revisions with one revision a nonexistent", func(t *testing.T) { - // increase count to 2 revisions - test.serviceUpdate(t, "hello", []string{"--env", "TARGET=kn", "--port", "8888"}) - - existRevision1 := test.findRevisionByGeneration(t, "hello", 1) - existRevision2 := test.findRevisionByGeneration(t, "hello", 2) - nonexistRevision := "hello-nonexist" - - test.revisionMultipleDelete(t, []string{existRevision1, existRevision2, nonexistRevision}) - }) - - t.Run("delete hello service and return no error", func(t *testing.T) { - test.serviceDelete(t, "hello") - }) + test, err := NewE2eTest() + assert.NilError(t, err) + defer func() { + assert.NilError(t, test.Teardown()) + }() + + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + t.Log("create hello service and return no error") + test.serviceCreate(t, r, "hello") + + t.Log("describe revision from hello service with print flags") + revName := test.findRevision(t, r, "hello") + test.revisionDescribeWithPrintFlags(t, r, revName) + + t.Log("update hello service and increase the count of configuration generation") + test.serviceUpdate(t, r, "hello", "--env", "TARGET=kn", "--port", "8888") + + t.Log("show a list of revisions sorted by the count of configuration generation") + test.revisionListWithService(t, r, "hello") + + t.Log("delete latest revision from hello service and return no error") + revName = test.findRevision(t, r, "hello") + test.revisionDelete(t, r, revName) + + t.Log("delete three revisions with one revision a nonexistent") + + // increase count to 2 revisions + test.serviceUpdate(t, r, "hello", "--env", "TARGET=kn", "--port", "8888") + + existRevision1 := test.findRevisionByGeneration(t, r, "hello", 1) + existRevision2 := test.findRevisionByGeneration(t, r, "hello", 2) + nonexistRevision := "hello-nonexist" + + test.revisionMultipleDelete(t, r, existRevision1, existRevision2, nonexistRevision) + + t.Log("delete hello service and return no error") + test.serviceDelete(t, r, "hello") } -func (test *e2eTest) revisionListWithService(t *testing.T, serviceNames ...string) { +func (test *e2eTest) revisionListWithService(t *testing.T, r *KnRunResultCollector, serviceNames ...string) { for _, svcName := range serviceNames { - confGen := test.findConfigurationGeneration(t, svcName) - - out, err := test.kn.RunWithOpts([]string{"revision", "list", "-s", svcName}, runOpts{}) - assert.NilError(t, err) + confGen := test.findConfigurationGeneration(t, r, svcName) + out := test.kn.Run("revision", "list", "-s", svcName) + r.AssertNoError(out) - outputLines := strings.Split(out, "\n") + outputLines := strings.Split(out.Stdout, "\n") // Ignore the last line because it is an empty string caused by splitting a line break // at the end of the output string for _, line := range outputLines[1 : len(outputLines)-1] { - revName := test.findRevisionByGeneration(t, svcName, confGen) + revName := test.findRevisionByGeneration(t, r, svcName, confGen) assert.Check(t, util.ContainsAll(line, revName, svcName, strconv.Itoa(confGen))) confGen-- } } } -func (test *e2eTest) revisionDelete(t *testing.T, revName string) { - out, err := test.kn.RunWithOpts([]string{"revision", "delete", revName}, runOpts{}) - assert.NilError(t, err) - - assert.Check(t, util.ContainsAll(out, "Revision", revName, "deleted", "namespace", test.kn.namespace)) +func (test *e2eTest) revisionDelete(t *testing.T, r *KnRunResultCollector, revName string) { + out := test.kn.Run("revision", "delete", revName) + assert.Check(t, util.ContainsAll(out.Stdout, "Revision", revName, "deleted", "namespace", test.kn.namespace)) + r.AssertNoError(out) } -func (test *e2eTest) revisionMultipleDelete(t *testing.T, revisionNames []string) { - existRevision1 := revisionNames[0] - existRevision2 := revisionNames[1] - nonexistRevision := revisionNames[2] - - out, err := test.kn.RunWithOpts([]string{"revision", "list"}, runOpts{NoNamespace: false}) - assert.NilError(t, err) - assert.Check(t, strings.Contains(out, existRevision1), "Required revision1 does not exist") - assert.Check(t, strings.Contains(out, existRevision2), "Required revision2 does not exist") +func (test *e2eTest) revisionMultipleDelete(t *testing.T, r *KnRunResultCollector, existRevision1, existRevision2, nonexistRevision string) { + out := test.kn.Run("revision", "list") + r.AssertNoError(out) + assert.Check(t, strings.Contains(out.Stdout, existRevision1), "Required revision1 does not exist") + assert.Check(t, strings.Contains(out.Stdout, existRevision2), "Required revision2 does not exist") - out, err = test.kn.RunWithOpts([]string{"revision", "delete", existRevision1, existRevision2, nonexistRevision}, runOpts{NoNamespace: false}) + out = test.kn.Run("revision", "delete", existRevision1, existRevision2, nonexistRevision) + r.AssertNoError(out) - assert.Check(t, util.ContainsAll(out, "Revision", existRevision1, "deleted", "namespace", test.kn.namespace), "Failed to get 'deleted' first revision message") - assert.Check(t, util.ContainsAll(out, "Revision", existRevision2, "deleted", "namespace", test.kn.namespace), "Failed to get 'deleted' second revision message") - assert.Check(t, util.ContainsAll(out, "revisions.serving.knative.dev", nonexistRevision, "not found"), "Failed to get 'not found' error") + assert.Check(t, util.ContainsAll(out.Stdout, "Revision", existRevision1, "deleted", "namespace", test.kn.namespace), "Failed to get 'deleted' first revision message") + assert.Check(t, util.ContainsAll(out.Stdout, "Revision", existRevision2, "deleted", "namespace", test.kn.namespace), "Failed to get 'deleted' second revision message") + assert.Check(t, util.ContainsAll(out.Stdout, "revisions.serving.knative.dev", nonexistRevision, "not found"), "Failed to get 'not found' error") } -func (test *e2eTest) revisionDescribeWithPrintFlags(t *testing.T, revName string) { - out, err := test.kn.RunWithOpts([]string{"revision", "describe", revName, "-o=name"}, runOpts{}) - assert.NilError(t, err) - +func (test *e2eTest) revisionDescribeWithPrintFlags(t *testing.T, r *KnRunResultCollector, revName string) { + out := test.kn.Run("revision", "describe", revName, "-o=name") + r.AssertNoError(out) expectedName := fmt.Sprintf("revision.serving.knative.dev/%s", revName) - assert.Equal(t, strings.TrimSpace(out), expectedName) + assert.Equal(t, strings.TrimSpace(out.Stdout), expectedName) } -func (test *e2eTest) findRevision(t *testing.T, serviceName string) string { - revName, err := test.kn.RunWithOpts([]string{"revision", "list", "-s", serviceName, "-o=jsonpath={.items[0].metadata.name}"}, runOpts{}) - assert.NilError(t, err) - if strings.Contains(revName, "No resources found.") { +func (test *e2eTest) findRevision(t *testing.T, r *KnRunResultCollector, serviceName string) string { + out := test.kn.Run("revision", "list", "-s", serviceName, "-o=jsonpath={.items[0].metadata.name}") + r.AssertNoError(out) + if strings.Contains(out.Stdout, "No resources") { t.Errorf("Could not find revision name.") } - return revName + return out.Stdout } -func (test *e2eTest) findRevisionByGeneration(t *testing.T, serviceName string, generation int) string { - maxGen := test.findConfigurationGeneration(t, serviceName) - revName, err := test.kn.RunWithOpts([]string{"revision", "list", "-s", serviceName, - fmt.Sprintf("-o=jsonpath={.items[%d].metadata.name}", maxGen-generation)}, runOpts{}) - assert.NilError(t, err) - if strings.Contains(revName, "No resources found.") { +func (test *e2eTest) findRevisionByGeneration(t *testing.T, r *KnRunResultCollector, serviceName string, generation int) string { + maxGen := test.findConfigurationGeneration(t, r, serviceName) + out := test.kn.Run("revision", "list", "-s", serviceName, + fmt.Sprintf("-o=jsonpath={.items[%d].metadata.name}", maxGen-generation)) + r.AssertNoError(out) + if strings.Contains(out.Stdout, "No resources found.") { t.Errorf("Could not find revision name.") } - return revName + return out.Stdout } -func (test *e2eTest) findConfigurationGeneration(t *testing.T, serviceName string) int { - confGenStr, err := test.kn.RunWithOpts([]string{"revision", "list", "-s", serviceName, "-o=jsonpath={.items[0].metadata.labels.serving\\.knative\\.dev/configurationGeneration}"}, runOpts{}) - assert.NilError(t, err) - if confGenStr == "" { +func (test *e2eTest) findConfigurationGeneration(t *testing.T, r *KnRunResultCollector, serviceName string) int { + out := test.kn.Run("revision", "list", "-s", serviceName, "-o=jsonpath={.items[0].metadata.labels.serving\\.knative\\.dev/configurationGeneration}") + r.AssertNoError(out) + if out.Stdout == "" { t.Errorf("Could not find configuration generation.") } - confGen, err := strconv.Atoi(confGenStr) + confGen, err := strconv.Atoi(out.Stdout) if err != nil { t.Errorf("Invalid type of configuration generation: %s", err) } diff --git a/test/e2e/route_test.go b/test/e2e/route_test.go index 5bb6de00ab..be989c8fe1 100644 --- a/test/e2e/route_test.go +++ b/test/e2e/route_test.go @@ -28,73 +28,70 @@ import ( func TestRoute(t *testing.T) { t.Parallel() - test := NewE2eTest(t) - test.Setup(t) - defer test.Teardown(t) + test, err := NewE2eTest() + assert.NilError(t, err) + defer func() { + assert.NilError(t, test.Teardown()) + }() + + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() - t.Run("create hello service and return no error", func(t *testing.T) { - test.serviceCreate(t, "hello") - }) + t.Log("create hello service and return no error") + test.serviceCreate(t, r, "hello") - t.Run("return a list of routes", func(t *testing.T) { - test.routeList(t) - }) + t.Log("return a list of routes") + test.routeList(t, r) - t.Run("return a list of routes associated with hello service", func(t *testing.T) { - test.routeListWithArgument(t, "hello") - }) + t.Log("return a list of routes associated with hello service") + test.routeListWithArgument(t, r, "hello") - t.Run("return a list of routes associated with hello service with print flags", func(t *testing.T) { - test.routeListWithPrintFlags(t, "hello") - }) + t.Log("return a list of routes associated with hello service with print flags") + test.routeListWithPrintFlags(t, r, "hello") - t.Run("describe route from hello service", func(t *testing.T) { - test.routeDescribe(t, "hello") - }) + t.Log("describe route from hello service") + test.routeDescribe(t, r, "hello") - t.Run("describe route from hello service with print flags", func(t *testing.T) { - test.routeDescribeWithPrintFlags(t, "hello") - }) + t.Log("describe route from hello service with print flags") + test.routeDescribeWithPrintFlags(t, r, "hello") - t.Run("delete hello service and return no error", func(t *testing.T) { - test.serviceDelete(t, "hello") - }) + t.Log("delete hello service and return no error") + test.serviceDelete(t, r, "hello") } -func (test *e2eTest) routeList(t *testing.T) { - out, err := test.kn.RunWithOpts([]string{"route", "list"}, runOpts{}) - assert.NilError(t, err) +func (test *e2eTest) routeList(t *testing.T, r *KnRunResultCollector) { + out := test.kn.Run("route", "list") expectedHeaders := []string{"NAME", "URL", "READY"} - assert.Check(t, util.ContainsAll(out, expectedHeaders...)) + assert.Check(t, util.ContainsAll(out.Stdout, expectedHeaders...)) + r.AssertNoError(out) } -func (test *e2eTest) routeListWithArgument(t *testing.T, routeName string) { - out, err := test.kn.RunWithOpts([]string{"route", "list", routeName}, runOpts{}) - assert.NilError(t, err) +func (test *e2eTest) routeListWithArgument(t *testing.T, r *KnRunResultCollector, routeName string) { + out := test.kn.Run("route", "list", routeName) - assert.Check(t, util.ContainsAll(out, routeName)) + assert.Check(t, util.ContainsAll(out.Stdout, routeName)) + r.AssertNoError(out) } -func (test *e2eTest) routeDescribe(t *testing.T, routeName string) { - out, err := test.kn.RunWithOpts([]string{"route", "describe", routeName}, runOpts{}) - assert.NilError(t, err) +func (test *e2eTest) routeDescribe(t *testing.T, r *KnRunResultCollector, routeName string) { + out := test.kn.Run("route", "describe", routeName) - assert.Check(t, util.ContainsAll(out, + assert.Check(t, util.ContainsAll(out.Stdout, routeName, test.kn.namespace, "URL", "Service", "Traffic", "Targets", "Conditions")) + r.AssertNoError(out) } -func (test *e2eTest) routeDescribeWithPrintFlags(t *testing.T, routeName string) { - out, err := test.kn.RunWithOpts([]string{"route", "describe", routeName, "-o=name"}, runOpts{}) - assert.NilError(t, err) +func (test *e2eTest) routeDescribeWithPrintFlags(t *testing.T, r *KnRunResultCollector, routeName string) { + out := test.kn.Run("route", "describe", routeName, "-o=name") expectedName := fmt.Sprintf("route.serving.knative.dev/%s", routeName) - assert.Equal(t, strings.TrimSpace(out), expectedName) + assert.Equal(t, strings.TrimSpace(out.Stdout), expectedName) + r.AssertNoError(out) } -func (test *e2eTest) routeListWithPrintFlags(t *testing.T, names ...string) { - out, err := test.kn.RunWithOpts([]string{"route", "list", "-o=jsonpath={.items[*].metadata.name}"}, runOpts{}) - assert.NilError(t, err) - - assert.Check(t, util.ContainsAll(out, names...)) +func (test *e2eTest) routeListWithPrintFlags(t *testing.T, r *KnRunResultCollector, names ...string) { + out := test.kn.Run("route", "list", "-o=jsonpath={.items[*].metadata.name}") + assert.Check(t, util.ContainsAll(out.Stdout, names...)) + r.AssertNoError(out) } diff --git a/test/e2e/service_options_test.go b/test/e2e/service_options_test.go index e1acb58f4d..9e01391657 100644 --- a/test/e2e/service_options_test.go +++ b/test/e2e/service_options_test.go @@ -27,183 +27,133 @@ import ( func TestServiceOptions(t *testing.T) { t.Parallel() - test := NewE2eTest(t) - test.Setup(t) - defer test.Teardown(t) - - t.Run("create and validate service with concurrency options", func(t *testing.T) { - test.serviceCreateWithOptions(t, "svc1", []string{"--concurrency-limit", "250", "--concurrency-target", "300"}) - test.validateServiceConcurrencyTarget(t, "svc1", "300") - test.validateServiceConcurrencyLimit(t, "svc1", "250") - }) - - t.Run("update and validate service with concurrency limit", func(t *testing.T) { - test.serviceUpdate(t, "svc1", []string{"--concurrency-limit", "300"}) - test.validateServiceConcurrencyLimit(t, "svc1", "300") - }) - - t.Run("update concurrency options with invalid values for service", func(t *testing.T) { - command := []string{"service", "update", "svc1", "--concurrency-limit", "-1", "--concurrency-target", "0"} - _, err := test.kn.RunWithOpts(command, runOpts{NoNamespace: false, AllowError: true}) - assert.ErrorContains(t, err, "invalid") - }) - - t.Run("returns steady concurrency options for service", func(t *testing.T) { - test.validateServiceConcurrencyLimit(t, "svc1", "300") - test.validateServiceConcurrencyTarget(t, "svc1", "300") - }) - - t.Run("delete service", func(t *testing.T) { - test.serviceDelete(t, "svc1") - }) - - t.Run("create and validate service with min/max scale options ", func(t *testing.T) { - test.serviceCreateWithOptions(t, "svc2", []string{"--min-scale", "1", "--max-scale", "3"}) - test.validateServiceMinScale(t, "svc2", "1") - test.validateServiceMaxScale(t, "svc2", "3") - }) - - t.Run("update and validate service with max scale option", func(t *testing.T) { - test.serviceUpdate(t, "svc2", []string{"--max-scale", "2"}) - test.validateServiceMaxScale(t, "svc2", "2") - }) - - t.Run("delete service", func(t *testing.T) { - test.serviceDelete(t, "svc2") - }) - - t.Run("create, update and validate service with annotations", func(t *testing.T) { - test.serviceCreateWithOptions(t, "svc3", []string{"--annotation", "alpha=wolf", "--annotation", "brave=horse"}) - test.validateServiceAnnotations(t, "svc3", map[string]string{"alpha": "wolf", "brave": "horse"}) - test.serviceUpdate(t, "svc3", []string{"--annotation", "alpha=direwolf", "--annotation", "brave-"}) - test.validateServiceAnnotations(t, "svc3", map[string]string{"alpha": "direwolf", "brave": ""}) - test.serviceDelete(t, "svc3") - }) - - t.Run("create, update and validate service with autoscale window option", func(t *testing.T) { - test.serviceCreateWithOptions(t, "svc4", []string{"--autoscale-window", "1m"}) - test.validateAutoscaleWindow(t, "svc4", "1m") - test.serviceUpdate(t, "svc4", []string{"--autoscale-window", "15s"}) - test.validateAutoscaleWindow(t, "svc4", "15s") - test.serviceDelete(t, "svc4") - }) - - t.Run("create, update and validate service with cmd and arg options", func(t *testing.T) { - test.serviceCreateWithOptions(t, "svc5", []string{"--cmd", "/go/bin/helloworld"}) - test.validateContainerField(t, "svc5", "command", "[/go/bin/helloworld]") - test.serviceUpdate(t, "svc5", []string{"--arg", "myArg1", "--arg", "--myArg2"}) - test.validateContainerField(t, "svc5", "args", "[myArg1 --myArg2]") - test.serviceUpdate(t, "svc5", []string{"--arg", "myArg1"}) - test.validateContainerField(t, "svc5", "args", "[myArg1]") - }) + test, err := NewE2eTest() + assert.NilError(t, err) + defer func() { + assert.NilError(t, test.Teardown()) + }() + + r := NewKnRunResultCollector(t) + + t.Log("create and validate service with concurrency options") + defer r.DumpIfFailed() + + test.serviceCreateWithOptions(t, r, "svc1", "--concurrency-limit", "250", "--concurrency-target", "300") + test.validateServiceConcurrencyTarget(t, r, "svc1", "300") + test.validateServiceConcurrencyLimit(t, r, "svc1", "250") + + t.Log("update and validate service with concurrency limit") + test.serviceUpdate(t, r, "svc1", "--concurrency-limit", "300") + test.validateServiceConcurrencyLimit(t, r, "svc1", "300") + + t.Log("update concurrency options with invalid values for service") + out := test.kn.Run("service", "update", "svc1", "--concurrency-limit", "-1", "--concurrency-target", "0") + r.AssertError(out) + assert.Check(t, util.ContainsAll(out.Stderr, "invalid")) + + t.Log("returns steady concurrency options for service") + test.validateServiceConcurrencyLimit(t, r, "svc1", "300") + test.validateServiceConcurrencyTarget(t, r, "svc1", "300") + + t.Log("delete service") + test.serviceDelete(t, r, "svc1") + + t.Log("create and validate service with min/max scale options ") + test.serviceCreateWithOptions(t, r, "svc2", "--min-scale", "1", "--max-scale", "3") + test.validateServiceMinScale(t, r, "svc2", "1") + test.validateServiceMaxScale(t, r, "svc2", "3") + + t.Log("update and validate service with max scale option") + test.serviceUpdate(t, r, "svc2", "--max-scale", "2") + test.validateServiceMaxScale(t, r, "svc2", "2") + + t.Log("delete service") + test.serviceDelete(t, r, "svc2") + + t.Log("create, update and validate service with annotations") + test.serviceCreateWithOptions(t, r, "svc3", "--annotation", "alpha=wolf", "--annotation", "brave=horse") + test.validateServiceAnnotations(t, r, "svc3", map[string]string{"alpha": "wolf", "brave": "horse"}) + test.serviceUpdate(t, r, "svc3", "--annotation", "alpha=direwolf", "--annotation", "brave-") + test.validateServiceAnnotations(t, r, "svc3", map[string]string{"alpha": "direwolf", "brave": ""}) + test.serviceDelete(t, r, "svc3") + + t.Log("create, update and validate service with autoscale window option") + test.serviceCreateWithOptions(t, r, "svc4", "--autoscale-window", "1m") + test.validateAutoscaleWindow(t, r, "svc4", "1m") + test.serviceUpdate(t, r, "svc4", "--autoscale-window", "15s") + test.validateAutoscaleWindow(t, r, "svc4", "15s") + test.serviceDelete(t, r, "svc4") + + t.Log("create, update and validate service with cmd and arg options") + test.serviceCreateWithOptions(t, r, "svc5", "--cmd", "/go/bin/helloworld") + test.validateContainerField(t, r, "svc5", "command", "[/go/bin/helloworld]") + test.serviceUpdate(t, r, "svc5", "--arg", "myArg1", "--arg", "--myArg2") + test.validateContainerField(t, r, "svc5", "args", "[myArg1 --myArg2]") + test.serviceUpdate(t, r, "svc5", "--arg", "myArg1") + test.validateContainerField(t, r, "svc5", "args", "[myArg1]") } -func (test *e2eTest) serviceCreateWithOptions(t *testing.T, serviceName string, options []string) { +func (test *e2eTest) serviceCreateWithOptions(t *testing.T, r *KnRunResultCollector, serviceName string, options ...string) { command := []string{"service", "create", serviceName, "--image", KnDefaultTestImage} command = append(command, options...) - out, err := test.kn.RunWithOpts(command, runOpts{NoNamespace: false}) - assert.NilError(t, err) - assert.Check(t, util.ContainsAll(out, "service", serviceName, "Creating", "namespace", test.kn.namespace, "Ready")) + out := test.kn.Run(command...) + assert.Check(t, util.ContainsAll(out.Stdout, "service", serviceName, "Creating", "namespace", test.kn.namespace, "Ready")) + r.AssertNoError(out) } -func (test *e2eTest) validateServiceConcurrencyLimit(t *testing.T, serviceName, concurrencyLimit string) { +func (test *e2eTest) validateServiceConcurrencyLimit(t *testing.T, r *KnRunResultCollector, serviceName, concurrencyLimit string) { jsonpath := "jsonpath={.items[0].spec.template.spec.containerConcurrency}" - out, err := test.kn.RunWithOpts([]string{"service", "list", serviceName, "-o", jsonpath}, runOpts{}) - assert.NilError(t, err) - if out != "" { - assert.Equal(t, out, concurrencyLimit) - } else { - // case where server returns fields like spec.runLatest.configuration.revisionTemplate.spec.containerConcurrency - // TODO: Remove this case when `runLatest` field is deprecated altogether / v1beta1 - jsonpath = "jsonpath={.items[0].spec.runLatest.configuration.revisionTemplate.spec.containerConcurrency}" - out, err := test.kn.RunWithOpts([]string{"service", "list", serviceName, "-o", jsonpath}, runOpts{}) - assert.NilError(t, err) - assert.Equal(t, out, concurrencyLimit) - } + out := test.kn.Run("service", "list", serviceName, "-o", jsonpath) + assert.Equal(t, out.Stdout, concurrencyLimit) + r.AssertNoError(out) } -func (test *e2eTest) validateServiceConcurrencyTarget(t *testing.T, serviceName, concurrencyTarget string) { +func (test *e2eTest) validateServiceConcurrencyTarget(t *testing.T, r *KnRunResultCollector, serviceName, concurrencyTarget string) { jsonpath := "jsonpath={.items[0].spec.template.metadata.annotations.autoscaling\\.knative\\.dev/target}" - out, err := test.kn.RunWithOpts([]string{"service", "list", serviceName, "-o", jsonpath}, runOpts{}) - assert.NilError(t, err) - if out != "" { - assert.Equal(t, out, concurrencyTarget) - } else { - // case where server returns fields like spec.runLatest.configuration.revisionTemplate.spec.containerConcurrency - // TODO: Remove this case when `runLatest` field is deprecated altogether / v1beta1 - jsonpath = "jsonpath={.items[0].spec.runLatest.configuration.revisionTemplate.metadata.annotations.autoscaling\\.knative\\.dev/target}" - out, err := test.kn.RunWithOpts([]string{"service", "list", serviceName, "-o", jsonpath}, runOpts{}) - assert.NilError(t, err) - assert.Equal(t, out, concurrencyTarget) - } + out := test.kn.Run("service", "list", serviceName, "-o", jsonpath) + assert.Equal(t, out.Stdout, concurrencyTarget) + r.AssertNoError(out) } -func (test *e2eTest) validateAutoscaleWindow(t *testing.T, serviceName, window string) { +func (test *e2eTest) validateAutoscaleWindow(t *testing.T, r *KnRunResultCollector, serviceName, window string) { jsonpath := "jsonpath={.items[0].spec.template.metadata.annotations.autoscaling\\.knative\\.dev/window}" - out, err := test.kn.RunWithOpts([]string{"service", "list", serviceName, "-o", jsonpath}, runOpts{}) - assert.NilError(t, err) - assert.Equal(t, out, window) + out := test.kn.Run("service", "list", serviceName, "-o", jsonpath) + assert.Equal(t, out.Stdout, window) + r.AssertNoError(out) } -func (test *e2eTest) validateServiceMinScale(t *testing.T, serviceName, minScale string) { +func (test *e2eTest) validateServiceMinScale(t *testing.T, r *KnRunResultCollector, serviceName, minScale string) { jsonpath := "jsonpath={.items[0].spec.template.metadata.annotations.autoscaling\\.knative\\.dev/minScale}" - out, err := test.kn.RunWithOpts([]string{"service", "list", serviceName, "-o", jsonpath}, runOpts{}) - assert.NilError(t, err) - if out != "" { - assert.Equal(t, minScale, out) - } else { - // case where server could return either old or new fields - // #TODO: remove this when old fields are deprecated, v1beta1 - jsonpath = "jsonpath={.items[0].spec.runLatest.configuration.revisionTemplate.metadata.annotations.autoscaling\\.knative\\.dev/minScale}" - out, err := test.kn.RunWithOpts([]string{"service", "list", serviceName, "-o", jsonpath}, runOpts{}) - assert.NilError(t, err) - assert.Equal(t, minScale, out) - } + out := test.kn.Run("service", "list", serviceName, "-o", jsonpath) + assert.Equal(t, out.Stdout, minScale) + r.AssertNoError(out) } -func (test *e2eTest) validateServiceMaxScale(t *testing.T, serviceName, maxScale string) { +func (test *e2eTest) validateServiceMaxScale(t *testing.T, r *KnRunResultCollector, serviceName, maxScale string) { jsonpath := "jsonpath={.items[0].spec.template.metadata.annotations.autoscaling\\.knative\\.dev/maxScale}" - out, err := test.kn.RunWithOpts([]string{"service", "list", serviceName, "-o", jsonpath}, runOpts{}) - assert.NilError(t, err) - if out != "" { - assert.Equal(t, maxScale, out) - } else { - // case where server could return either old or new fields - // #TODO: remove this when old fields are deprecated, v1beta1 - jsonpath = "jsonpath={.items[0].spec.runLatest.configuration.revisionTemplate.metadata.annotations.autoscaling\\.knative\\.dev/maxScale}" - out, err := test.kn.RunWithOpts([]string{"service", "list", serviceName, "-o", jsonpath}, runOpts{}) - assert.NilError(t, err) - assert.Equal(t, maxScale, out) - } + out := test.kn.Run("service", "list", serviceName, "-o", jsonpath) + assert.Equal(t, out.Stdout, maxScale) + r.AssertNoError(out) } -func (test *e2eTest) validateServiceAnnotations(t *testing.T, serviceName string, annotations map[string]string) { +func (test *e2eTest) validateServiceAnnotations(t *testing.T, r *KnRunResultCollector, serviceName string, annotations map[string]string) { metadataAnnotationsJsonpathFormat := "jsonpath={.metadata.annotations.%s}" templateAnnotationsJsonpathFormat := "jsonpath={.spec.template.metadata.annotations.%s}" - oldTemplateAnnotationsJsonpathFormat := "jsonpath={.spec.runLatest.configuration.revisionTemplate.metadata.annotations.%s}" for k, v := range annotations { - out, err := test.kn.RunWithOpts([]string{"service", "describe", serviceName, "-o", fmt.Sprintf(metadataAnnotationsJsonpathFormat, k)}, runOpts{}) - assert.NilError(t, err) - assert.Equal(t, v, out) - - out, err = test.kn.RunWithOpts([]string{"service", "describe", serviceName, "-o", fmt.Sprintf(templateAnnotationsJsonpathFormat, k)}, runOpts{}) - assert.NilError(t, err) - if out != "" || v == "" { - assert.Equal(t, v, out) - } else { - // case where server returns fields like spec.runLatest.configuration.revisionTemplate.metadata.annotations - // TODO: Remove this case when `runLatest` field is deprecated altogether / v1beta1 - out, err := test.kn.RunWithOpts([]string{"service", "describe", serviceName, "-o", fmt.Sprintf(oldTemplateAnnotationsJsonpathFormat, k)}, runOpts{}) - assert.NilError(t, err) - assert.Equal(t, v, out) - } + out := test.kn.Run("service", "describe", serviceName, "-o", fmt.Sprintf(metadataAnnotationsJsonpathFormat, k)) + assert.Equal(t, v, out.Stdout) + r.AssertNoError(out) + + out = test.kn.Run("service", "describe", serviceName, "-o", fmt.Sprintf(templateAnnotationsJsonpathFormat, k)) + assert.Equal(t, v, out.Stdout) + r.AssertNoError(out) } } -func (test *e2eTest) validateContainerField(t *testing.T, serviceName, field, expected string) { +func (test *e2eTest) validateContainerField(t *testing.T, r *KnRunResultCollector, serviceName, field, expected string) { jsonpath := fmt.Sprintf("jsonpath={.items[0].spec.template.spec.containers[0].%s}", field) - out, err := test.kn.RunWithOpts([]string{"service", "list", serviceName, "-o", jsonpath}, runOpts{}) - assert.NilError(t, err) - assert.Equal(t, out, expected) + out := test.kn.Run("service", "list", serviceName, "-o", jsonpath) + assert.Equal(t, out.Stdout, expected) + r.AssertNoError(out) } diff --git a/test/e2e/service_test.go b/test/e2e/service_test.go index 1ce32e1cce..ed0c8d0707 100644 --- a/test/e2e/service_test.go +++ b/test/e2e/service_test.go @@ -23,76 +23,79 @@ import ( "testing" "gotest.tools/assert" + + "knative.dev/client/pkg/util" ) func TestService(t *testing.T) { t.Parallel() - test := NewE2eTest(t) - test.Setup(t) - defer test.Teardown(t) - - t.Run("create hello service duplicate and get service already exists error", func(t *testing.T) { - test.serviceCreate(t, "hello") - test.serviceCreateDuplicate(t, "hello") - }) - - t.Run("return valid info about hello service with print flags", func(t *testing.T) { - test.serviceDescribeWithPrintFlags(t, "hello") - }) - - t.Run("delete hello service repeatedly and get an error", func(t *testing.T) { - test.serviceDelete(t, "hello") - test.serviceDeleteNonexistent(t, "hello") - }) - - t.Run("delete two services with a service nonexistent", func(t *testing.T) { - test.serviceCreate(t, "hello") - test.serviceMultipleDelete(t, []string{"hello123", "hello"}) - }) -} - -func (test *e2eTest) serviceCreateDuplicate(t *testing.T, serviceName string) { - out, err := test.kn.RunWithOpts([]string{"service", "list", serviceName}, runOpts{NoNamespace: false}) + test, err := NewE2eTest() assert.NilError(t, err) - assert.Check(t, strings.Contains(out, serviceName), "The service does not exist yet") + defer func() { + assert.NilError(t, test.Teardown()) + }() + + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + t.Log("create hello service duplicate and get service already exists error") + test.serviceCreate(t, r, "hello") + test.serviceCreateDuplicate(t, r, "hello") + + t.Log("return valid info about hello service with print flags") + test.serviceDescribeWithPrintFlags(t, r, "hello") + + t.Log("delete hello service repeatedly and get an error") + test.serviceDelete(t, r, "hello") + test.serviceDeleteNonexistent(t, r, "hello") - _, err = test.kn.RunWithOpts([]string{"service", "create", serviceName, - "--image", KnDefaultTestImage}, runOpts{NoNamespace: false, AllowError: true}) + t.Log("delete two services with a service nonexistent") + test.serviceCreate(t, r, "hello") - assert.ErrorContains(t, err, "the service already exists") + test.serviceMultipleDelete(t, r, "hello", "bla123") } -func (test *e2eTest) serviceDescribeWithPrintFlags(t *testing.T, serviceName string) { - out, err := test.kn.RunWithOpts([]string{"service", "describe", serviceName, "-o=name"}, runOpts{}) - assert.NilError(t, err) +func (test *e2eTest) serviceCreateDuplicate(t *testing.T, r *KnRunResultCollector, serviceName string) { + out := test.kn.Run("service", "list", serviceName) + out.ErrorExpected = true + r.AssertNoError(out) + assert.Check(t, strings.Contains(out.Stdout, serviceName), "The service does not exist yet") - expectedName := fmt.Sprintf("service.serving.knative.dev/%s", serviceName) - assert.Equal(t, strings.TrimSpace(out), expectedName) + out = test.kn.Run("service", "create", serviceName, "--image", KnDefaultTestImage) + out.ErrorExpected = true + r.AssertError(out) + assert.Check(t, util.ContainsAll(out.Stderr, "the service already exists")) } -func (test *e2eTest) serviceDeleteNonexistent(t *testing.T, serviceName string) { - out, err := test.kn.RunWithOpts([]string{"service", "list", serviceName}, runOpts{NoNamespace: false}) - assert.NilError(t, err) - assert.Check(t, !strings.Contains(out, serviceName), "The service exists") +func (test *e2eTest) serviceDescribeWithPrintFlags(t *testing.T, r *KnRunResultCollector, serviceName string) { + out := test.kn.Run("service", "describe", serviceName, "-o=name") + r.AssertNoError(out) - out, err = test.kn.RunWithOpts([]string{"service", "delete", serviceName}, runOpts{NoNamespace: false, AllowError: true}) + expectedName := fmt.Sprintf("service.serving.knative.dev/%s", serviceName) + assert.Equal(t, strings.TrimSpace(out.Stdout), expectedName) +} + +func (test *e2eTest) serviceDeleteNonexistent(t *testing.T, r *KnRunResultCollector, serviceName string) { + out := test.kn.Run("service", "list", serviceName) + r.AssertNoError(out) + assert.Check(t, !strings.Contains(out.Stdout, serviceName), "The service exists") - expectedErr := fmt.Sprintf(`services.serving.knative.dev "%s" not found`, serviceName) - assert.Check(t, strings.Contains(out, expectedErr), "Failed to get 'not found' error") + out = test.kn.Run("service", "delete", serviceName) + r.AssertNoError(out) + assert.Check(t, util.ContainsAll(out.Stdout, "hello", "not found"), "Failed to get 'not found' error") } -func (test *e2eTest) serviceMultipleDelete(t *testing.T, serviceName []string) { - existService := serviceName[1] - nonexistService := serviceName[0] - out, err := test.kn.RunWithOpts([]string{"service", "list"}, runOpts{NoNamespace: false}) - assert.NilError(t, err) - assert.Check(t, strings.Contains(out, existService), "The service not exists") - assert.Check(t, !strings.Contains(out, nonexistService), "The service exists") +func (test *e2eTest) serviceMultipleDelete(t *testing.T, r *KnRunResultCollector, existService, nonexistService string) { + out := test.kn.Run("service", "list") + r.AssertNoError(out) + assert.Check(t, strings.Contains(out.Stdout, existService), "The service ", existService, " does not exist (but is expected to exist)") + assert.Check(t, !strings.Contains(out.Stdout, nonexistService), "The service", nonexistService, " exists (but is supposed to be not)") - out, err = test.kn.RunWithOpts([]string{"service", "delete", serviceName[0], serviceName[1]}, runOpts{NoNamespace: false, AllowError: true}) + out = test.kn.Run("service", "delete", existService, nonexistService) + r.AssertNoError(out) expectedSuccess := fmt.Sprintf(`Service '%s' successfully deleted in namespace '%s'.`, existService, test.kn.namespace) expectedErr := fmt.Sprintf(`services.serving.knative.dev "%s" not found`, nonexistService) - assert.Check(t, strings.Contains(out, expectedSuccess), "Failed to get 'successfully deleted' message") - assert.Check(t, strings.Contains(out, expectedErr), "Failed to get 'not found' error") + assert.Check(t, strings.Contains(out.Stdout, expectedSuccess), "Failed to get 'successfully deleted' message") + assert.Check(t, strings.Contains(out.Stdout, expectedErr), "Failed to get 'not found' error") } diff --git a/test/e2e/source_apiserver_test.go b/test/e2e/source_apiserver_test.go index 1cbacd1c75..2e065d1deb 100644 --- a/test/e2e/source_apiserver_test.go +++ b/test/e2e/source_apiserver_test.go @@ -18,9 +18,11 @@ package e2e import ( + "fmt" "strings" "testing" + "github.com/pkg/errors" "gotest.tools/assert" "knative.dev/client/pkg/util" ) @@ -34,114 +36,107 @@ const ( func TestSourceApiServer(t *testing.T) { t.Parallel() - test := NewE2eTest(t) - test.Setup(t) + test, err := NewE2eTest() + assert.NilError(t, err) defer func() { - test.tearDownForSourceApiServer(t) - test.Teardown(t) + err1 := test.tearDownForSourceApiServer() + err2 := test.Teardown() + assert.NilError(t, err1) + assert.NilError(t, err2) }() + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + test.setupForSourceApiServer(t) - test.serviceCreate(t, "testsvc0") - - t.Run("create apiserver sources with a sink to a service", func(t *testing.T) { - test.apiServerSourceCreate(t, "testapisource0", "Event:v1:true", "testsa", "svc:testsvc0") - test.apiServerSourceCreate(t, "testapisource1", "Event:v1", "testsa", "svc:testsvc0") - }) - - t.Run("delete apiserver sources", func(t *testing.T) { - test.apiServerSourceDelete(t, "testapisource0") - test.apiServerSourceDelete(t, "testapisource1") - }) - - t.Run("create apiserver source with a missing sink service", func(t *testing.T) { - test.apiServerSourceCreateMissingSink(t, "testapisource2", "Event:v1:true", "testsa", "svc:unknown") - }) - - t.Run("update apiserver source sink service", func(t *testing.T) { - test.apiServerSourceCreate(t, "testapisource3", "Event:v1:true", "testsa", "svc:testsvc0") - test.serviceCreate(t, "testsvc1") - test.apiServerSourceUpdateSink(t, "testapisource3", "svc:testsvc1") - jpSinkRefNameInSpec := "jsonpath={.spec.sink.ref.name}" - out, err := test.getResourceFieldsWithJSONPath(t, "apiserversource", "testapisource3", jpSinkRefNameInSpec) - assert.NilError(t, err) - assert.Equal(t, out, "testsvc1") - // TODO(navidshaikh): Verify the source's status with synchronous create/update - }) -} + test.serviceCreate(t, r, "testsvc0") + + t.Log("create apiserver sources with a sink to a service") + test.apiServerSourceCreate(t, r, "testapisource0", "Event:v1:true", "testsa", "svc:testsvc0") + test.apiServerSourceCreate(t, r, "testapisource1", "Event:v1", "testsa", "svc:testsvc0") + + t.Log("delete apiserver sources") + test.apiServerSourceDelete(t, r, "testapisource0") + test.apiServerSourceDelete(t, r, "testapisource1") -func (test *e2eTest) apiServerSourceCreate(t *testing.T, sourceName string, resources string, sa string, sink string) { - out, err := test.kn.RunWithOpts([]string{"source", "apiserver", "create", sourceName, - "--resource", resources, "--service-account", sa, "--sink", sink}, runOpts{NoNamespace: false}) + t.Log("create apiserver source with a missing sink service") + test.apiServerSourceCreateMissingSink(t, r, "testapisource2", "Event:v1:true", "testsa", "svc:unknown") + + t.Log("update apiserver source sink service") + test.apiServerSourceCreate(t, r, "testapisource3", "Event:v1:true", "testsa", "svc:testsvc0") + test.serviceCreate(t, r, "testsvc1") + test.apiServerSourceUpdateSink(t, r, "testapisource3", "svc:testsvc1") + jpSinkRefNameInSpec := "jsonpath={.spec.sink.ref.name}" + out, err := test.getResourceFieldsWithJSONPath("apiserversource", "testapisource3", jpSinkRefNameInSpec) assert.NilError(t, err) - assert.Check(t, util.ContainsAllIgnoreCase(out, "apiserver", "source", sourceName, "created", "namespace", test.kn.namespace)) + assert.Equal(t, out, "testsvc1") + // TODO(navidshaikh): Verify the source's status with synchronous create/update } -func (test *e2eTest) apiServerSourceCreateMissingSink(t *testing.T, sourceName string, resources string, sa string, sink string) { - _, err := test.kn.RunWithOpts([]string{"source", "apiserver", "create", sourceName, - "--resource", resources, "--service-account", sa, "--sink", sink}, runOpts{NoNamespace: false, AllowError: true}) - assert.ErrorContains(t, err, "services.serving.knative.dev", "not found") +func (test *e2eTest) apiServerSourceCreate(t *testing.T, r *KnRunResultCollector, sourceName string, resources string, sa string, sink string) { + out := test.kn.Run("source", "apiserver", "create", sourceName, "--resource", resources, "--service-account", sa, "--sink", sink) + r.AssertNoError(out) + assert.Check(t, util.ContainsAllIgnoreCase(out.Stdout, "apiserver", "source", sourceName, "created", "namespace", test.kn.namespace)) } -func (test *e2eTest) apiServerSourceDelete(t *testing.T, sourceName string) { - out, err := test.kn.RunWithOpts([]string{"source", "apiserver", "delete", sourceName}, runOpts{NoNamespace: false}) - assert.NilError(t, err) - assert.Check(t, util.ContainsAllIgnoreCase(out, "apiserver", "source", sourceName, "deleted", "namespace", test.kn.namespace)) +func (test *e2eTest) apiServerSourceCreateMissingSink(t *testing.T, r *KnRunResultCollector, sourceName string, resources string, sa string, sink string) { + out := test.kn.Run("source", "apiserver", "create", sourceName, "--resource", resources, "--service-account", sa, "--sink", sink) + r.AssertError(out) + assert.Check(t, util.ContainsAll(out.Stderr, "services.serving.knative.dev", "not found")) } -func (test *e2eTest) setupForSourceApiServer(t *testing.T) { - kubectl := kubectl{t, Logger{}} +func (test *e2eTest) apiServerSourceDelete(t *testing.T, r *KnRunResultCollector, sourceName string) { + out := test.kn.Run("source", "apiserver", "delete", sourceName) + r.AssertNoError(out) + assert.Check(t, util.ContainsAllIgnoreCase(out.Stdout, "apiserver", "source", sourceName, "deleted", "namespace", test.kn.namespace)) +} - saCmd := []string{"create", "serviceaccount", testServiceAccount, "--namespace", test.kn.namespace} - _, err := kubectl.RunWithOpts(saCmd, runOpts{}) - if err != nil { - t.Fatalf("Error executing '%s'. Error: %v", strings.Join(saCmd, " "), err.Error()) - } +func (test *e2eTest) setupForSourceApiServer(t *testing.T) { + _, err := kubectl{test.kn.namespace}.Run("create", "serviceaccount", testServiceAccount) + assert.NilError(t, err) - crCmd := []string{"create", "clusterrole", clusterRolePrefix + test.kn.namespace, "--verb=get,list,watch", "--resource=events,namespaces"} - _, err = kubectl.RunWithOpts(crCmd, runOpts{}) - if err != nil { - t.Fatalf("Error executing '%s'. Error: %v", strings.Join(crCmd, " "), err.Error()) - } + _, err = kubectl{}.Run("create", "clusterrole", clusterRolePrefix+test.kn.namespace, "--verb=get,list,watch", "--resource=events,namespaces") + assert.NilError(t, err) - crbCmd := []string{"create", "clusterrolebinding", clusterRoleBindingPrefix + test.kn.namespace, "--clusterrole=" + clusterRolePrefix + test.kn.namespace, "--serviceaccount=" + test.kn.namespace + ":" + testServiceAccount} - _, err = kubectl.RunWithOpts(crbCmd, runOpts{}) - if err != nil { - t.Fatalf("Error executing '%s'. Error: %v", strings.Join(crbCmd, " "), err.Error()) - } + _, err = kubectl{}.Run( + "create", + "clusterrolebinding", + clusterRoleBindingPrefix+test.kn.namespace, + "--clusterrole="+clusterRolePrefix+test.kn.namespace, + "--serviceaccount="+test.kn.namespace+":"+testServiceAccount) + assert.NilError(t, err) } -func (test *e2eTest) tearDownForSourceApiServer(t *testing.T) { - kubectl := kubectl{t, Logger{}} +func (test *e2eTest) tearDownForSourceApiServer() error { - saCmd := []string{"delete", "serviceaccount", testServiceAccount, "--namespace", test.kn.namespace} - _, err := kubectl.RunWithOpts(saCmd, runOpts{}) + saCmd := []string{"delete", "serviceaccount", testServiceAccount} + _, err := kubectl{test.kn.namespace}.Run(saCmd...) if err != nil { - t.Fatalf("Error executing '%s'. Error: %v", strings.Join(saCmd, " "), err.Error()) + return errors.Wrap(err, fmt.Sprintf("Error executing '%s'", strings.Join(saCmd, " "))) } crCmd := []string{"delete", "clusterrole", clusterRolePrefix + test.kn.namespace} - _, err = kubectl.RunWithOpts(crCmd, runOpts{}) + _, err = kubectl{}.Run(crCmd...) if err != nil { - t.Fatalf("Error executing '%s'. Error: %v", strings.Join(crCmd, " "), err.Error()) + return errors.Wrap(err, fmt.Sprintf("Error executing '%s'", strings.Join(saCmd, " "))) } crbCmd := []string{"delete", "clusterrolebinding", clusterRoleBindingPrefix + test.kn.namespace} - _, err = kubectl.RunWithOpts(crbCmd, runOpts{}) + _, err = kubectl{}.Run(crbCmd...) if err != nil { - t.Fatalf("Error executing '%s'. Error: %v", strings.Join(crbCmd, " "), err.Error()) + return errors.Wrap(err, fmt.Sprintf("Error executing '%s'", strings.Join(saCmd, " "))) } + return nil } -func (test *e2eTest) apiServerSourceUpdateSink(t *testing.T, sourceName string, sink string) { - out, err := test.kn.RunWithOpts([]string{"source", "apiserver", "update", sourceName, "--sink", sink}, runOpts{}) - assert.NilError(t, err) - assert.Check(t, util.ContainsAll(out, sourceName, "updated", "namespace", test.kn.namespace)) +func (test *e2eTest) apiServerSourceUpdateSink(t *testing.T, r *KnRunResultCollector, sourceName string, sink string) { + out := test.kn.Run("source", "apiserver", "update", sourceName, "--sink", sink) + r.AssertNoError(out) + assert.Check(t, util.ContainsAll(out.Stdout, sourceName, "updated", "namespace", test.kn.namespace)) } -func (test *e2eTest) getResourceFieldsWithJSONPath(t *testing.T, resource, name, jsonpath string) (string, error) { - kubectl := kubectl{t, Logger{}} - out, err := kubectl.RunWithOpts([]string{"get", resource, name, "-o", jsonpath, "-n", test.kn.namespace}, runOpts{}) +func (test *e2eTest) getResourceFieldsWithJSONPath(resource, name, jsonpath string) (string, error) { + out, err := kubectl{test.kn.namespace}.Run("get", resource, name, "-o", jsonpath, "-n", test.kn.namespace) if err != nil { return "", err } diff --git a/test/e2e/source_binding_test.go b/test/e2e/source_binding_test.go index 3f33ab96af..a44240ccf7 100644 --- a/test/e2e/source_binding_test.go +++ b/test/e2e/source_binding_test.go @@ -26,48 +26,47 @@ import ( func TestSourceBinding(t *testing.T) { t.Parallel() - test := NewE2eTest(t) - test.Setup(t) - defer test.Teardown(t) - - test.serviceCreate(t, "testsvc0") - - t.Run("create source binding", func(t *testing.T) { - test.sourceBindingCreate(t, "my-binding0", "Deployment:apps/v1:myapp", "svc:testsvc0") - }) - - t.Run("delete source binding", func(t *testing.T) { - test.sourceBindingDelete(t, "my-binding0") - }) - - t.Run("update source binding", func(t *testing.T) { - test.sourceBindingCreate(t, "my-binding1", "Deployment:apps/v1:myapp", "svc:testsvc0") - test.serviceCreate(t, "testsvc1") - test.sourceBindingUpdate(t, "my-binding1", "Deployment:apps/v1:myapp", "svc:testsvc1") - jpSinkRefNameInSpec := "jsonpath={.spec.sink.ref.name}" - out, err := test.getResourceFieldsWithJSONPath(t, "sinkbindings.sources.knative.dev", "my-binding1", jpSinkRefNameInSpec) - assert.NilError(t, err) - assert.Equal(t, out, "testsvc1") - }) + test, err := NewE2eTest() + assert.NilError(t, err) + defer func() { + assert.NilError(t, test.Teardown()) + }() -} + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + test.serviceCreate(t, r, "testsvc0") + + t.Log("create source binding") + test.sourceBindingCreate(t, r, "my-binding0", "Deployment:apps/v1:myapp", "svc:testsvc0") + + t.Log("delete source binding") + test.sourceBindingDelete(t, r, "my-binding0") -func (test *e2eTest) sourceBindingCreate(t *testing.T, bindingName string, subject string, sink string) { - out, err := test.kn.RunWithOpts([]string{"source", "binding", "create", bindingName, - "--subject", subject, "--sink", sink}, runOpts{NoNamespace: false}) + t.Log("update source binding") + test.sourceBindingCreate(t, r, "my-binding1", "Deployment:apps/v1:myapp", "svc:testsvc0") + test.serviceCreate(t, r, "testsvc1") + test.sourceBindingUpdate(t, r, "my-binding1", "Deployment:apps/v1:myapp", "svc:testsvc1") + jpSinkRefNameInSpec := "jsonpath={.spec.sink.ref.name}" + out, err := test.getResourceFieldsWithJSONPath("sinkbindings.sources.knative.dev", "my-binding1", jpSinkRefNameInSpec) assert.NilError(t, err) - assert.Check(t, util.ContainsAllIgnoreCase(out, "Sink", "binding", bindingName, "created", "namespace", test.kn.namespace)) + assert.Equal(t, out, "testsvc1") } -func (test *e2eTest) sourceBindingDelete(t *testing.T, bindingName string) { - out, err := test.kn.RunWithOpts([]string{"source", "binding", "delete", bindingName}, runOpts{NoNamespace: false}) - assert.NilError(t, err) - assert.Check(t, util.ContainsAllIgnoreCase(out, "Sink", "binding", bindingName, "deleted", "namespace", test.kn.namespace)) +func (test *e2eTest) sourceBindingCreate(t *testing.T, r *KnRunResultCollector, bindingName string, subject string, sink string) { + out := test.kn.Run("source", "binding", "create", bindingName, "--subject", subject, "--sink", sink) + r.AssertNoError(out) + assert.Check(t, util.ContainsAllIgnoreCase(out.Stdout, "Sink", "binding", bindingName, "created", "namespace", test.kn.namespace)) } -func (test *e2eTest) sourceBindingUpdate(t *testing.T, bindingName string, subject string, sink string) { - out, err := test.kn.RunWithOpts([]string{"source", "binding", "update", bindingName, - "--subject", subject, "--sink", sink}, runOpts{}) - assert.NilError(t, err) - assert.Check(t, util.ContainsAll(out, bindingName, "updated", "namespace", test.kn.namespace)) +func (test *e2eTest) sourceBindingDelete(t *testing.T, r *KnRunResultCollector, bindingName string) { + out := test.kn.Run("source", "binding", "delete", bindingName) + r.AssertNoError(out) + assert.Check(t, util.ContainsAllIgnoreCase(out.Stdout, "Sink", "binding", bindingName, "deleted", "namespace", test.kn.namespace)) +} + +func (test *e2eTest) sourceBindingUpdate(t *testing.T, r *KnRunResultCollector, bindingName string, subject string, sink string) { + out := test.kn.Run("source", "binding", "update", bindingName, "--subject", subject, "--sink", sink) + r.AssertNoError(out) + assert.Check(t, util.ContainsAll(out.Stdout, bindingName, "updated", "namespace", test.kn.namespace)) } diff --git a/test/e2e/source_list_types_test.go b/test/e2e/source_list_types_test.go index dd014b05fb..e8f998cb00 100644 --- a/test/e2e/source_list_types_test.go +++ b/test/e2e/source_list_types_test.go @@ -26,25 +26,28 @@ import ( func TestSourceListTypes(t *testing.T) { t.Parallel() - test := NewE2eTest(t) - test.Setup(t) - defer test.Teardown(t) + test, err := NewE2eTest() + assert.NilError(t, err) + defer func() { + assert.NilError(t, test.Teardown()) + }() + + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() - t.Run("List available source types", func(t *testing.T) { - output := test.sourceListTypes(t) - assert.Check(t, util.ContainsAll(output, "TYPE", "NAME", "DESCRIPTION", "CronJob", "ApiServer")) - }) + t.Log("List available source types") + output := test.sourceListTypes(t, r) + assert.Check(t, util.ContainsAll(output, "TYPE", "NAME", "DESCRIPTION", "CronJob", "ApiServer")) - t.Run("List available source types in YAML format", func(t *testing.T) { - output := test.sourceListTypes(t, "-oyaml") - assert.Check(t, util.ContainsAll(output, "apiextensions.k8s.io/v1beta1", "CustomResourceDefinition", "CronJob", "ApiServer")) + t.Log("List available source types in YAML format") - }) + output = test.sourceListTypes(t, r, "-oyaml") + assert.Check(t, util.ContainsAll(output, "apiextensions.k8s.io/v1beta1", "CustomResourceDefinition", "CronJob", "ApiServer")) } -func (test *e2eTest) sourceListTypes(t *testing.T, args ...string) (out string) { +func (test *e2eTest) sourceListTypes(t *testing.T, r *KnRunResultCollector, args ...string) string { cmd := append([]string{"source", "list-types"}, args...) - out, err := test.kn.RunWithOpts(cmd, runOpts{}) - assert.NilError(t, err) - return + out := test.kn.Run(cmd...) + r.AssertNoError(out) + return out.Stdout } diff --git a/test/e2e/tekton_test.go b/test/e2e/tekton_test.go index 60f1efc11c..ee5cace8d5 100644 --- a/test/e2e/tekton_test.go +++ b/test/e2e/tekton_test.go @@ -34,53 +34,55 @@ const ( ) func TestTektonPipeline(t *testing.T) { - test := NewE2eTest(t) - test.Setup(t) + test, err := NewE2eTest() + assert.NilError(t, err) + defer func() { + assert.NilError(t, test.Teardown()) + }() - kubectl := kubectl{t, Logger{}} + kubectl := kubectl{test.namespace} basedir := currentDir(t) + "/../resources/tekton" // create secret for the kn-deployer-account service account - _, err := kubectl.RunWithOpts([]string{"create", "-n", test.env.Namespace, "secret", + _, err = kubectl.Run("create", "-n", test.namespace, "secret", "generic", "container-registry", - "--from-file=.dockerconfigjson=" + Flags.DockerConfigJSON, - "--type=kubernetes.io/dockerconfigjson"}, runOpts{}) + "--from-file=.dockerconfigjson="+Flags.DockerConfigJSON, + "--type=kubernetes.io/dockerconfigjson") assert.NilError(t, err) - _, err = kubectl.RunWithOpts([]string{"apply", "-n", test.env.Namespace, "-f", basedir + "/kn-deployer-rbac.yaml"}, runOpts{}) + _, err = kubectl.Run("apply", "-f", basedir+"/kn-deployer-rbac.yaml") assert.NilError(t, err) - _, err = kubectl.RunWithOpts([]string{"apply", "-n", test.env.Namespace, "-f", basedir + "/buildah.yaml"}, runOpts{}) + _, err = kubectl.Run("apply", "-f", basedir+"/buildah.yaml") assert.NilError(t, err) - _, err = kubectl.RunWithOpts([]string{"apply", "-n", test.env.Namespace, "-f", "https://raw.githubusercontent.com/tektoncd/catalog/master/kn/kn.yaml"}, runOpts{}) + _, err = kubectl.Run("apply", "-f", "https://raw.githubusercontent.com/tektoncd/catalog/master/kn/kn.yaml") assert.NilError(t, err) - _, err = kubectl.RunWithOpts([]string{"apply", "-n", test.env.Namespace, "-f", basedir + "/kn-pipeline.yaml"}, runOpts{}) + _, err = kubectl.Run("apply", "-f", basedir+"/kn-pipeline.yaml") assert.NilError(t, err) - _, err = kubectl.RunWithOpts([]string{"apply", "-n", test.env.Namespace, "-f", basedir + "/kn-pipeline-resource.yaml"}, runOpts{}) + _, err = kubectl.Run("apply", "-f", basedir+"/kn-pipeline-resource.yaml") assert.NilError(t, err) - _, err = kubectl.RunWithOpts([]string{"create", "-n", test.env.Namespace, "-f", basedir + "/kn-pipeline-run.yaml"}, runOpts{}) + _, err = kubectl.Run("create", "-f", basedir+"/kn-pipeline-run.yaml") assert.NilError(t, err) - err = waitForPipelineSuccess(t, kubectl, test.env.Namespace) + err = waitForPipelineSuccess(kubectl) assert.NilError(t, err) - const serviceName = "hello" - out, err := test.kn.RunWithOpts([]string{"service", "describe", serviceName}, runOpts{NoNamespace: false}) - assert.NilError(t, err) - assert.Assert(t, util.ContainsAll(out, serviceName, test.kn.namespace)) - assert.Assert(t, util.ContainsAll(out, "Conditions", "ConfigurationsReady", "Ready", "RoutesReady")) + r := NewKnRunResultCollector(t) - // tear down only if the test passes, we want to keep the pods otherwise - test.Teardown(t) + const serviceName = "hello" + out := test.kn.Run("service", "describe", serviceName) + r.AssertNoError(out) + assert.Assert(t, util.ContainsAll(out.Stdout, serviceName, test.kn.namespace)) + assert.Assert(t, util.ContainsAll(out.Stdout, "Conditions", "ConfigurationsReady", "Ready", "RoutesReady")) } -func waitForPipelineSuccess(t *testing.T, k kubectl, namespace string) error { +func waitForPipelineSuccess(k kubectl) error { return wait.PollImmediate(Interval, Timeout, func() (bool, error) { - out, err := k.RunWithOpts([]string{"get", "pipelinerun", "-n", namespace, "-o=jsonpath='{.items[0].status.conditions[?(@.type==\"Succeeded\")].status}'"}, runOpts{}) + out, err := k.Run("get", "pipelinerun", "-o=jsonpath='{.items[0].status.conditions[?(@.type==\"Succeeded\")].status}'") return strings.Contains(out, "True"), err }) } diff --git a/test/e2e/traffic_split_test.go b/test/e2e/traffic_split_test.go index 1606c08960..a4f0c51dcc 100644 --- a/test/e2e/traffic_split_test.go +++ b/test/e2e/traffic_split_test.go @@ -73,282 +73,329 @@ func formatActualTargets(t *testing.T, actualTargets []string) (formattedTargets return } -// TestTrafficSplit runs different e2e tests for service traffic splitting and verifies the traffic targets from service status +// TestTrafficSplitSuite runs different e2e tests for service traffic splitting and verifies the traffic targets from service status func TestTrafficSplit(t *testing.T) { t.Parallel() - test := NewE2eTest(t) - test.Setup(t) - defer test.Teardown(t) + test, err := NewE2eTest() + assert.NilError(t, err) + defer func() { + assert.NilError(t, test.Teardown()) + }() serviceBase := "echo" - t.Run("tag two revisions as v1 and v2 and give 50-50% share", + t.Run("50:50", func(t *testing.T) { - serviceName := getServiceNameAndIncrement(serviceBase) - test.serviceCreate(t, serviceName) + t.Log("tag two revisions as v1 and v2 and give 50-50% share") + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + serviceName := getNextServiceName(serviceBase) + test.serviceCreate(t, r, serviceName) rev1 := fmt.Sprintf("%s-rev-1", serviceName) - test.serviceUpdateWithOptions(t, serviceName, []string{"--env", "TARGET=v1", "--revision-name", rev1}) + test.serviceUpdateWithOptions(t, r, serviceName, "--env", "TARGET=v1", "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.serviceUpdateWithOptions(t, serviceName, []string{"--env", "TARGET=v2", "--revision-name", rev2}) + test.serviceUpdateWithOptions(t, r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) tflags := []string{"--tag", fmt.Sprintf("%s=v1,%s=v2", rev1, rev2), "--traffic", "v1=50,v2=50"} - test.serviceUpdateWithOptions(t, serviceName, tflags) + test.serviceUpdateWithOptions(t, r, serviceName, tflags...) // make ordered fields per tflags (tag, revision, percent, latest) expectedTargets := []TargetFields{newTargetFields("v1", rev1, 50, false), newTargetFields("v2", rev2, 50, false)} - test.verifyTargets(t, serviceName, expectedTargets) - test.serviceDelete(t, serviceName) + test.verifyTargets(t, r, serviceName, expectedTargets) + test.serviceDelete(t, r, serviceName) }, ) - t.Run("ramp/up down a revision to 20% adjusting other traffic to accommodate", + t.Run("20:80", func(t *testing.T) { - serviceName := getServiceNameAndIncrement(serviceBase) - test.serviceCreate(t, serviceName) + t.Log("ramp/up down a revision to 20% adjusting other traffic to accommodate") + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + serviceName := getNextServiceName(serviceBase) + test.serviceCreate(t, r, serviceName) rev1 := fmt.Sprintf("%s-rev-1", serviceName) - test.serviceUpdateWithOptions(t, serviceName, []string{"--env", "TARGET=v1", "--revision-name", rev1}) + test.serviceUpdateWithOptions(t, r, serviceName, "--env", "TARGET=v1", "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.serviceUpdateWithOptions(t, serviceName, []string{"--env", "TARGET=v2", "--revision-name", rev2}) + test.serviceUpdateWithOptions(t, r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) - tflags := []string{"--traffic", fmt.Sprintf("%s=20,%s=80", rev1, rev2)} // traffic by revision name - test.serviceUpdateWithOptions(t, serviceName, tflags) + test.serviceUpdateWithOptions(t, r, serviceName, "--traffic", fmt.Sprintf("%s=20,%s=80", rev1, rev2)) expectedTargets := []TargetFields{newTargetFields("", rev1, 20, false), newTargetFields("", rev2, 80, false)} - test.verifyTargets(t, serviceName, expectedTargets) - test.serviceDelete(t, serviceName) + test.verifyTargets(t, r, serviceName, expectedTargets) + test.serviceDelete(t, r, serviceName) }, ) - t.Run("tag a revision as candidate, without otherwise changing any traffic split", + t.Run("TagCandidate", func(t *testing.T) { - serviceName := getServiceNameAndIncrement(serviceBase) + t.Log("tag a revision as candidate, without otherwise changing any traffic split") + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + serviceName := getNextServiceName(serviceBase) rev1 := fmt.Sprintf("%s-rev-1", serviceName) - test.serviceCreateWithOptions(t, serviceName, []string{"--revision-name", rev1}) + test.serviceCreateWithOptions(t, r, serviceName, "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.serviceUpdateWithOptions(t, serviceName, []string{"--env", "TARGET=v1", "--revision-name", rev2}) + test.serviceUpdateWithOptions(t, r, serviceName, "--env", "TARGET=v1", "--revision-name", rev2) - tflags := []string{"--tag", fmt.Sprintf("%s=%s", rev1, "candidate")} // no traffic, append new target with tag in traffic block - test.serviceUpdateWithOptions(t, serviceName, tflags) + // no traffic, append new target with tag in traffic block + test.serviceUpdateWithOptions(t, r, serviceName, "--tag", fmt.Sprintf("%s=%s", rev1, "candidate")) expectedTargets := []TargetFields{newTargetFields("", rev2, 100, true), newTargetFields("candidate", rev1, 0, false)} - test.verifyTargets(t, serviceName, expectedTargets) - test.serviceDelete(t, serviceName) + test.verifyTargets(t, r, serviceName, expectedTargets) + test.serviceDelete(t, r, serviceName) }, ) - t.Run("tag a revision as candidate, set 2% traffic adjusting other traffic to accommodate", + t.Run("TagCandidate:2:98", func(t *testing.T) { - serviceName := getServiceNameAndIncrement(serviceBase) + t.Log("tag a revision as candidate, set 2% traffic adjusting other traffic to accommodate") + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + serviceName := getNextServiceName(serviceBase) rev1 := fmt.Sprintf("%s-rev-1", serviceName) - test.serviceCreateWithOptions(t, serviceName, []string{"--revision-name", rev1}) + test.serviceCreateWithOptions(t, r, serviceName, "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.serviceUpdateWithOptions(t, serviceName, []string{"--env", "TARGET=v1", "--revision-name", rev2}) + test.serviceUpdateWithOptions(t, r, serviceName, "--env", "TARGET=v1", "--revision-name", rev2) - tflags := []string{"--tag", fmt.Sprintf("%s=%s", rev1, "candidate"), - "--traffic", "candidate=2%,@latest=98%"} // traffic by tag name and use % at the end - test.serviceUpdateWithOptions(t, serviceName, tflags) + // traffic by tag name and use % at the end + test.serviceUpdateWithOptions(t, r, serviceName, + "--tag", fmt.Sprintf("%s=%s", rev1, "candidate"), + "--traffic", "candidate=2%,@latest=98%") expectedTargets := []TargetFields{newTargetFields("", rev2, 98, true), newTargetFields("candidate", rev1, 2, false)} - test.verifyTargets(t, serviceName, expectedTargets) - test.serviceDelete(t, serviceName) + test.verifyTargets(t, r, serviceName, expectedTargets) + test.serviceDelete(t, r, serviceName) }, ) - t.Run("update tag for a revision from candidate to current, tag current is present on another revision", + t.Run("TagCurrent", func(t *testing.T) { - serviceName := getServiceNameAndIncrement(serviceBase) + t.Log("update tag for a revision from candidate to current, tag current is present on another revision") + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + serviceName := getNextServiceName(serviceBase) // make available 3 revisions for service first rev1 := fmt.Sprintf("%s-rev-1", serviceName) - test.serviceCreateWithOptions(t, serviceName, []string{"--revision-name", rev1}) + test.serviceCreateWithOptions(t, r, serviceName, "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.serviceUpdateWithOptions(t, serviceName, []string{"--env", "TARGET=v2", "--revision-name", rev2}) + test.serviceUpdateWithOptions(t, r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) rev3 := fmt.Sprintf("%s-rev-3", serviceName) - test.serviceUpdateWithOptions(t, serviceName, []string{"--env", "TARGET=v3", "--revision-name", rev3}) //note that this gives 100% traffic to latest revision (rev3) + test.serviceUpdateWithOptions(t, r, serviceName, "--env", "TARGET=v3", "--revision-name", rev3) //note that this gives 100% traffic to latest revision (rev3) // make existing state: tag current and candidate exist in traffic block - tflags := []string{"--tag", fmt.Sprintf("%s=current,%s=candidate", rev1, rev2)} - test.serviceUpdateWithOptions(t, serviceName, tflags) + test.serviceUpdateWithOptions(t, r, serviceName, "--tag", fmt.Sprintf("%s=current,%s=candidate", rev1, rev2)) // desired state of tags: update tag of revision (rev2) from candidate to current (which is present on rev1) - tflags = []string{"--untag", "current,candidate", "--tag", fmt.Sprintf("%s=current", rev2)} //untag first to update - test.serviceUpdateWithOptions(t, serviceName, tflags) + //untag first to update + test.serviceUpdateWithOptions(t, r, serviceName, + "--untag", "current,candidate", + "--tag", fmt.Sprintf("%s=current", rev2)) // there will be 2 targets in existing block 1. @latest, 2.for revision $rev2 // target for rev1 is removed as it had no traffic and we untagged it's tag current expectedTargets := []TargetFields{newTargetFields("", rev3, 100, true), newTargetFields("current", rev2, 0, false)} - test.verifyTargets(t, serviceName, expectedTargets) - test.serviceDelete(t, serviceName) + test.verifyTargets(t, r, serviceName, expectedTargets) + test.serviceDelete(t, r, serviceName) }, ) - t.Run("update tag from testing to staging for @latest revision", + t.Run("TagStagingLatest", func(t *testing.T) { - serviceName := getServiceNameAndIncrement(serviceBase) + t.Log("update tag from testing to staging for @latest revision") + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + serviceName := getNextServiceName(serviceBase) rev1 := fmt.Sprintf("%s-rev-1", serviceName) - test.serviceCreateWithOptions(t, serviceName, []string{"--revision-name", rev1}) + test.serviceCreateWithOptions(t, r, serviceName, "--revision-name", rev1) // make existing state: tag @latest as testing - tflags := []string{"--tag", "@latest=testing"} - test.serviceUpdateWithOptions(t, serviceName, tflags) + test.serviceUpdateWithOptions(t, r, serviceName, "--tag", "@latest=testing") // desired state: change tag from testing to staging - tflags = []string{"--untag", "testing", "--tag", "@latest=staging"} - test.serviceUpdateWithOptions(t, serviceName, tflags) + test.serviceUpdateWithOptions(t, r, serviceName, "--untag", "testing", "--tag", "@latest=staging") expectedTargets := []TargetFields{newTargetFields("staging", rev1, 100, true)} - test.verifyTargets(t, serviceName, expectedTargets) - test.serviceDelete(t, serviceName) + test.verifyTargets(t, r, serviceName, expectedTargets) + test.serviceDelete(t, r, serviceName) }, ) - t.Run("update tag from testing to staging for a revision (non @latest)", + t.Run("TagStagingNonLatest", func(t *testing.T) { - serviceName := getServiceNameAndIncrement(serviceBase) + t.Log("update tag from testing to staging for a revision (non @latest)") + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + serviceName := getNextServiceName(serviceBase) rev1 := fmt.Sprintf("%s-rev-1", serviceName) - test.serviceCreateWithOptions(t, serviceName, []string{"--revision-name", rev1}) + test.serviceCreateWithOptions(t, r, serviceName, "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.serviceUpdateWithOptions(t, serviceName, []string{"--env", "TARGET=v2", "--revision-name", rev2}) + test.serviceUpdateWithOptions(t, r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) // make existing state: tag a revision as testing - tflags := []string{"--tag", fmt.Sprintf("%s=testing", rev1)} - test.serviceUpdateWithOptions(t, serviceName, tflags) + test.serviceUpdateWithOptions(t, r, serviceName, "--tag", fmt.Sprintf("%s=testing", rev1)) // desired state: change tag from testing to staging - tflags = []string{"--untag", "testing", "--tag", fmt.Sprintf("%s=staging", rev1)} - test.serviceUpdateWithOptions(t, serviceName, tflags) + test.serviceUpdateWithOptions(t, r, serviceName, "--untag", "testing", "--tag", fmt.Sprintf("%s=staging", rev1)) expectedTargets := []TargetFields{newTargetFields("", rev2, 100, true), newTargetFields("staging", rev1, 0, false)} - test.verifyTargets(t, serviceName, expectedTargets) - test.serviceDelete(t, serviceName) + test.verifyTargets(t, r, serviceName, expectedTargets) + test.serviceDelete(t, r, serviceName) }, ) // test reducing number of targets from traffic blockdd - t.Run("remove a revision with tag old from traffic block entirely", + t.Run("RemoveTag", func(t *testing.T) { - serviceName := getServiceNameAndIncrement(serviceBase) + t.Log("remove a revision with tag old from traffic block entirely") + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + serviceName := getNextServiceName(serviceBase) rev1 := fmt.Sprintf("%s-rev-1", serviceName) - test.serviceCreateWithOptions(t, serviceName, []string{"--revision-name", rev1}) + test.serviceCreateWithOptions(t, r, serviceName, "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.serviceUpdateWithOptions(t, serviceName, []string{"--env", "TARGET=v2", "--revision-name", rev2}) + test.serviceUpdateWithOptions(t, r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) // existing state: traffic block having a revision with tag old and some traffic - tflags := []string{"--tag", fmt.Sprintf("%s=old", rev1), - "--traffic", "old=2,@latest=98"} - test.serviceUpdateWithOptions(t, serviceName, tflags) + test.serviceUpdateWithOptions(t, r, serviceName, + "--tag", fmt.Sprintf("%s=old", rev1), + "--traffic", "old=2,@latest=98") // desired state: remove revision with tag old - tflags = []string{"--untag", "old", "--traffic", "@latest=100"} - test.serviceUpdateWithOptions(t, serviceName, tflags) + test.serviceUpdateWithOptions(t, r, serviceName, "--untag", "old", "--traffic", "@latest=100") expectedTargets := []TargetFields{newTargetFields("", rev2, 100, true)} - test.verifyTargets(t, serviceName, expectedTargets) - test.serviceDelete(t, serviceName) + test.verifyTargets(t, r, serviceName, expectedTargets) + test.serviceDelete(t, r, serviceName) }, ) - t.Run("tag a revision as stable and current with 50-50% traffic", + t.Run("TagStable:50:50", func(t *testing.T) { - serviceName := getServiceNameAndIncrement(serviceBase) + t.Log("tag a revision as stable and current with 50-50% traffic") + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + serviceName := getNextServiceName(serviceBase) rev1 := fmt.Sprintf("%s-rev-1", serviceName) - test.serviceCreateWithOptions(t, serviceName, []string{"--revision-name", rev1}) + test.serviceCreateWithOptions(t, r, serviceName, "--revision-name", rev1) // existing state: traffic block having two targets - test.serviceUpdateWithOptions(t, serviceName, []string{"--env", "TARGET=v2"}) + test.serviceUpdateWithOptions(t, r, serviceName, "--env", "TARGET=v2") // desired state: tag non-@latest revision with two tags and 50-50% traffic each - tflags := []string{"--tag", fmt.Sprintf("%s=stable,%s=current", rev1, rev1), - "--traffic", "stable=50%,current=50%"} - test.serviceUpdateWithOptions(t, serviceName, tflags) + test.serviceUpdateWithOptions(t, r, serviceName, + "--tag", fmt.Sprintf("%s=stable,%s=current", rev1, rev1), + "--traffic", "stable=50%,current=50%") expectedTargets := []TargetFields{newTargetFields("stable", rev1, 50, false), newTargetFields("current", rev1, 50, false)} - test.verifyTargets(t, serviceName, expectedTargets) - test.serviceDelete(t, serviceName) + test.verifyTargets(t, r, serviceName, expectedTargets) + test.serviceDelete(t, r, serviceName) }, ) - t.Run("revert all traffic to latest ready revision of service", + t.Run("RevertToLatest", func(t *testing.T) { - serviceName := getServiceNameAndIncrement(serviceBase) + t.Log("revert all traffic to latest ready revision of service") + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + serviceName := getNextServiceName(serviceBase) rev1 := fmt.Sprintf("%s-rev-1", serviceName) - test.serviceCreateWithOptions(t, serviceName, []string{"--revision-name", rev1}) + test.serviceCreateWithOptions(t, r, serviceName, "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.serviceUpdateWithOptions(t, serviceName, []string{"--env", "TARGET=v2", "--revision-name", rev2}) + test.serviceUpdateWithOptions(t, r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) // existing state: latest ready revision not getting any traffic - tflags := []string{"--traffic", fmt.Sprintf("%s=100", rev1)} - test.serviceUpdateWithOptions(t, serviceName, tflags) + test.serviceUpdateWithOptions(t, r, serviceName, "--traffic", fmt.Sprintf("%s=100", rev1)) // desired state: revert traffic to latest ready revision - tflags = []string{"--traffic", "@latest=100"} - test.serviceUpdateWithOptions(t, serviceName, tflags) + test.serviceUpdateWithOptions(t, r, serviceName, "--traffic", "@latest=100") expectedTargets := []TargetFields{newTargetFields("", rev2, 100, true)} - test.verifyTargets(t, serviceName, expectedTargets) - test.serviceDelete(t, serviceName) + test.verifyTargets(t, r, serviceName, expectedTargets) + test.serviceDelete(t, r, serviceName) }, ) - t.Run("tag latest ready revision of service as current", + t.Run("TagLatestAsCurrent", func(t *testing.T) { - serviceName := getServiceNameAndIncrement(serviceBase) + t.Log("tag latest ready revision of service as current") + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + serviceName := getNextServiceName(serviceBase) // existing state: latest revision has no tag rev1 := fmt.Sprintf("%s-rev-1", serviceName) - test.serviceCreateWithOptions(t, serviceName, []string{"--revision-name", rev1}) + test.serviceCreateWithOptions(t, r, serviceName, "--revision-name", rev1) // desired state: tag latest ready revision as 'current' - tflags := []string{"--tag", "@latest=current"} - test.serviceUpdateWithOptions(t, serviceName, tflags) + test.serviceUpdateWithOptions(t, r, serviceName, "--tag", "@latest=current") expectedTargets := []TargetFields{newTargetFields("current", rev1, 100, true)} - test.verifyTargets(t, serviceName, expectedTargets) - test.serviceDelete(t, serviceName) + test.verifyTargets(t, r, serviceName, expectedTargets) + test.serviceDelete(t, r, serviceName) }, ) - t.Run("update tag for a revision as testing and assign all the traffic to it:", + t.Run("UpdateTag:100:0", func(t *testing.T) { - serviceName := getServiceNameAndIncrement(serviceBase) + t.Log("update tag for a revision as testing and assign all the traffic to it") + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + serviceName := getNextServiceName(serviceBase) rev1 := fmt.Sprintf("%s-rev-1", serviceName) - test.serviceCreateWithOptions(t, serviceName, []string{"--revision-name", rev1}) + test.serviceCreateWithOptions(t, r, serviceName, "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.serviceUpdateWithOptions(t, serviceName, []string{"--env", "TARGET=v2", "--revision-name", rev2}) + test.serviceUpdateWithOptions(t, r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) // existing state: two revision exists with traffic share and // each revision has tag and traffic portions - tflags := []string{"--tag", fmt.Sprintf("@latest=current,%s=candidate", rev1), - "--traffic", "current=90,candidate=10"} - test.serviceUpdateWithOptions(t, serviceName, tflags) + test.serviceUpdateWithOptions(t, r, serviceName, + "--tag", fmt.Sprintf("@latest=current,%s=candidate", rev1), + "--traffic", "current=90,candidate=10") // desired state: update tag for rev1 as testing (from candidate) with 100% traffic - tflags = []string{"--untag", "candidate", "--tag", fmt.Sprintf("%s=testing", rev1), - "--traffic", "testing=100"} - test.serviceUpdateWithOptions(t, serviceName, tflags) + test.serviceUpdateWithOptions(t, r, serviceName, + "--untag", "candidate", "--tag", fmt.Sprintf("%s=testing", rev1), + "--traffic", "testing=100") expectedTargets := []TargetFields{newTargetFields("current", rev2, 0, true), newTargetFields("testing", rev1, 100, false)} - test.verifyTargets(t, serviceName, expectedTargets) - test.serviceDelete(t, serviceName) + test.verifyTargets(t, r, serviceName, expectedTargets) + test.serviceDelete(t, r, serviceName) }, ) - t.Run("replace latest tag of a revision with old and give latest to another revision", + t.Run("TagReplace", func(t *testing.T) { - serviceName := getServiceNameAndIncrement(serviceBase) + t.Log("replace latest tag of a revision with old and give latest to another revision") + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() + + serviceName := getNextServiceName(serviceBase) rev1 := fmt.Sprintf("%s-rev-1", serviceName) - test.serviceCreateWithOptions(t, serviceName, []string{"--revision-name", rev1}) + test.serviceCreateWithOptions(t, r, serviceName, "--revision-name", rev1) rev2 := fmt.Sprintf("%s-rev-2", serviceName) - test.serviceUpdateWithOptions(t, serviceName, []string{"--env", "TARGET=v2", "--revision-name", rev2}) + test.serviceUpdateWithOptions(t, r, serviceName, "--env", "TARGET=v2", "--revision-name", rev2) // existing state: a revision exist with latest tag - tflags := []string{"--tag", fmt.Sprintf("%s=latest", rev1)} - test.serviceUpdateWithOptions(t, serviceName, tflags) + test.serviceUpdateWithOptions(t, r, serviceName, "--tag", fmt.Sprintf("%s=latest", rev1)) // desired state of revision tags: rev1=old rev2=latest - tflags = []string{"--untag", "latest", "--tag", fmt.Sprintf("%s=old,%s=latest", rev1, rev2)} - test.serviceUpdateWithOptions(t, serviceName, tflags) + test.serviceUpdateWithOptions(t, r, serviceName, + "--untag", "latest", + "--tag", fmt.Sprintf("%s=old,%s=latest", rev1, rev2)) expectedTargets := []TargetFields{newTargetFields("", rev2, 100, true), newTargetFields("old", rev1, 0, false), @@ -357,32 +404,34 @@ func TestTrafficSplit(t *testing.T) { // In spec of traffic block (not status) either latestReadyRevision:true or revisionName can be given per target newTargetFields("latest", rev2, 0, false)} - test.verifyTargets(t, serviceName, expectedTargets) - test.serviceDelete(t, serviceName) + test.verifyTargets(t, r, serviceName, expectedTargets) + test.serviceDelete(t, r, serviceName) }, ) } -func (test *e2eTest) verifyTargets(t *testing.T, serviceName string, expectedTargets []TargetFields) { - out := test.serviceDescribeWithJsonPath(t, serviceName, targetsJsonPath) +func (test *e2eTest) verifyTargets(t *testing.T, r *KnRunResultCollector, serviceName string, expectedTargets []TargetFields) { + out := test.serviceDescribeWithJsonPath(r, serviceName, targetsJsonPath) assert.Check(t, out != "") actualTargets, err := splitTargets(out, targetsSeparator, len(expectedTargets)) + if err != nil { + r.AddDump("service", serviceName, test.namespace) + } assert.NilError(t, err) formattedActualTargets := formatActualTargets(t, actualTargets) assert.DeepEqual(t, expectedTargets, formattedActualTargets) } -func (test *e2eTest) serviceDescribeWithJsonPath(t *testing.T, serviceName, jsonpath string) string { - command := []string{"service", "describe", serviceName, "-o", jsonpath} - out, err := test.kn.RunWithOpts(command, runOpts{}) - assert.NilError(t, err) - return out +func (test *e2eTest) serviceDescribeWithJsonPath(r *KnRunResultCollector, serviceName, jsonpath string) string { + out := test.kn.Run("service", "describe", serviceName, "-o", jsonpath) + r.AssertNoError(out) + return out.Stdout } -func (test *e2eTest) serviceUpdateWithOptions(t *testing.T, serviceName string, options []string) { +func (test *e2eTest) serviceUpdateWithOptions(t *testing.T, r *KnRunResultCollector, serviceName string, options ...string) { command := []string{"service", "update", serviceName} command = append(command, options...) - out, err := test.kn.RunWithOpts(command, runOpts{NoNamespace: false}) - assert.NilError(t, err) - assert.Check(t, util.ContainsAllIgnoreCase(out, "Service", serviceName, "updating", "namespace", test.kn.namespace)) + out := test.kn.Run(command...) + r.AssertNoError(out) + assert.Check(t, util.ContainsAllIgnoreCase(out.Stdout, "Service", serviceName, "updating", "namespace", test.kn.namespace)) } diff --git a/test/e2e/trigger_test.go b/test/e2e/trigger_test.go index ff4e5495ee..07f31eba68 100644 --- a/test/e2e/trigger_test.go +++ b/test/e2e/trigger_test.go @@ -29,49 +29,48 @@ import ( func TestBrokerTrigger(t *testing.T) { t.Parallel() - test := NewE2eTest(t) - test.Setup(t) - defer test.Teardown(t) - - err := test.lableNamespaceForDefaultBroker(t) + test, err := NewE2eTest() assert.NilError(t, err) - test.serviceCreate(t, "sinksvc0") - test.serviceCreate(t, "sinksvc1") - - t.Run("create triggers and list them", func(t *testing.T) { - test.triggerCreate(t, "trigger1", []string{"a=b"}, "sinksvc0") - test.triggerCreate(t, "trigger2", []string{"type=knative.dev.bar", "source=cronjob"}, "sinksvc1") - test.verifyTriggerList(t, []string{"trigger1", "trigger2"}) - }) + defer func() { + assert.NilError(t, test.Teardown()) + }() - t.Run("create a trigger and delete it", func(t *testing.T) { - test.triggerCreate(t, "deltrigger", []string{"a=b"}, "sinksvc0") - test.triggerDelete(t, "deltrigger") - test.verifyTriggerNotfound(t, "deltrigger") - }) + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() - t.Run("create a trigger, describe and update it", func(t *testing.T) { - test.triggerCreate(t, "updtrigger", []string{"a=b"}, "sinksvc0") - test.verifyTriggerDescribe(t, "updtrigger", []string{"a", "b"}, "default", "sinksvc0") - test.triggerUpdate(t, "updtrigger", "type=knative.dev.bar", "sinksvc1") - test.verifyTriggerDescribe(t, "updtrigger", []string{"a", "b", "type", "knative.dev.bar"}, "default", "sinksvc1") - }) - - t.Run("create trigger with error return", func(t *testing.T) { - test.triggerCreateMissingSink(t, "errtrigger", "notfound") - }) + err = test.lableNamespaceForDefaultBroker(t) + assert.NilError(t, err) + test.serviceCreate(t, r, "sinksvc0") + test.serviceCreate(t, r, "sinksvc1") + + t.Log("create triggers and list them") + test.triggerCreate(t, r, "trigger1", "sinksvc0", []string{"a=b"}) + test.triggerCreate(t, r, "trigger2", "sinksvc1", []string{"type=knative.dev.bar", "source=cronjob"}) + test.verifyTriggerList(t, r, "trigger1", "trigger2") + + t.Log("create a trigger and delete it") + test.triggerCreate(t, r, "deltrigger", "sinksvc0", []string{"a=b"}) + test.triggerDelete(t, r, "deltrigger") + test.verifyTriggerNotfound(t, r, "deltrigger") + + t.Log("create a trigger, describe and update it") + test.triggerCreate(t, r, "updtrigger", "sinksvc0", []string{"a=b"}) + test.verifyTriggerDescribe(t, r, "updtrigger", "default", "sinksvc0", []string{"a", "b"}) + test.triggerUpdate(t, r, "updtrigger", "type=knative.dev.bar", "sinksvc1") + test.verifyTriggerDescribe(t, r, "updtrigger", "default", "sinksvc1", []string{"a", "b", "type", "knative.dev.bar"}) + + t.Log("create trigger with error return") + test.triggerCreateMissingSink(t, r, "errtrigger", "notfound") } func (test *e2eTest) lableNamespaceForDefaultBroker(t *testing.T) error { - kubectl := kubectl{t, Logger{}} - - _, err := kubectl.RunWithOpts([]string{"label", "namespace", test.kn.namespace, "knative-eventing-injection=enabled"}, runOpts{}) + _, err := kubectl{}.Run("label", "namespace", test.kn.namespace, "knative-eventing-injection=enabled") if err != nil { t.Fatalf("Error executing 'kubectl label namespace %s knative-eventing-injection=enabled'. Error: %s", test.kn.namespace, err.Error()) } return wait.PollImmediate(10*time.Second, 5*time.Minute, func() (bool, error) { - out, err := kubectl.RunWithOpts([]string{"get", "broker", "-n", test.kn.namespace, "-o=jsonpath='{.items[0].status.conditions[?(@.type==\"Ready\")].status}'"}, runOpts{AllowError: true}) + out, err := kubectl{test.kn.namespace}.Run("get", "broker", "-o=jsonpath='{.items[0].status.conditions[?(@.type==\"Ready\")].status}'") if err != nil { return false, nil } else { @@ -80,47 +79,49 @@ func (test *e2eTest) lableNamespaceForDefaultBroker(t *testing.T) error { }) } -func (test *e2eTest) triggerCreate(t *testing.T, name string, filters []string, sinksvc string) { +func (test *e2eTest) triggerCreate(t *testing.T, r *KnRunResultCollector, name string, sinksvc string, filters []string) { args := []string{"trigger", "create", name, "--broker", "default", "--sink", "svc:" + sinksvc} for _, v := range filters { args = append(args, "--filter", v) } - out, err := test.kn.RunWithOpts(args, runOpts{NoNamespace: false}) - assert.NilError(t, err) - assert.Check(t, util.ContainsAllIgnoreCase(out, "Trigger", name, "created", "namespace", test.kn.namespace)) + out := test.kn.Run(args...) + r.AssertNoError(out) + assert.Check(t, util.ContainsAllIgnoreCase(out.Stdout, "Trigger", name, "created", "namespace", test.kn.namespace)) } -func (test *e2eTest) triggerCreateMissingSink(t *testing.T, name string, sinksvc string) { - _, err := test.kn.RunWithOpts([]string{"trigger", "create", name, "--broker", "default", "--sink", "svc:" + sinksvc}, runOpts{NoNamespace: false, AllowError: true}) - assert.ErrorContains(t, err, "services.serving.knative.dev", "not found") +func (test *e2eTest) triggerCreateMissingSink(t *testing.T, r *KnRunResultCollector, name string, sinksvc string) { + out := test.kn.Run("trigger", "create", name, "--broker", "default", "--sink", "svc:"+sinksvc) + r.AssertError(out) + assert.Check(t, util.ContainsAll(out.Stderr, "services.serving.knative.dev", "not found")) } -func (test *e2eTest) triggerDelete(t *testing.T, name string) { - out, err := test.kn.RunWithOpts([]string{"trigger", "delete", name}, runOpts{NoNamespace: false}) - assert.NilError(t, err) - assert.Check(t, util.ContainsAllIgnoreCase(out, "Trigger", name, "deleted", "namespace", test.kn.namespace)) +func (test *e2eTest) triggerDelete(t *testing.T, r *KnRunResultCollector, name string) { + out := test.kn.Run("trigger", "delete", name) + r.AssertNoError(out) + assert.Check(t, util.ContainsAllIgnoreCase(out.Stdout, "Trigger", name, "deleted", "namespace", test.kn.namespace)) } -func (test *e2eTest) triggerUpdate(t *testing.T, name string, filter string, sinksvc string) { - out, err := test.kn.RunWithOpts([]string{"trigger", "update", name, "--filter", filter, "--sink", "svc:" + sinksvc}, runOpts{NoNamespace: false}) - assert.NilError(t, err) - assert.Check(t, util.ContainsAllIgnoreCase(out, "Trigger", name, "updated", "namespace", test.kn.namespace)) +func (test *e2eTest) triggerUpdate(t *testing.T, r *KnRunResultCollector, name string, filter string, sinksvc string) { + out := test.kn.Run("trigger", "update", name, "--filter", filter, "--sink", "svc:"+sinksvc) + r.AssertNoError(out) + assert.Check(t, util.ContainsAllIgnoreCase(out.Stdout, "Trigger", name, "updated", "namespace", test.kn.namespace)) } -func (test *e2eTest) verifyTriggerList(t *testing.T, triggers []string) { - out, err := test.kn.RunWithOpts([]string{"trigger", "list"}, runOpts{NoNamespace: false}) - assert.NilError(t, err) - assert.Check(t, util.ContainsAllIgnoreCase(out, triggers...)) +func (test *e2eTest) verifyTriggerList(t *testing.T, r *KnRunResultCollector, triggers ...string) { + out := test.kn.Run("trigger", "list") + r.AssertNoError(out) + assert.Check(t, util.ContainsAllIgnoreCase(out.Stdout, triggers...)) } -func (test *e2eTest) verifyTriggerDescribe(t *testing.T, name string, filters []string, broker string, sink string) { - out, err := test.kn.RunWithOpts([]string{"trigger", "describe", name}, runOpts{NoNamespace: false}) - assert.NilError(t, err) - assert.Check(t, util.ContainsAllIgnoreCase(out, filters...)) - assert.Check(t, util.ContainsAllIgnoreCase(out, name, broker, sink)) +func (test *e2eTest) verifyTriggerDescribe(t *testing.T, r *KnRunResultCollector, name string, broker string, sink string, filters []string) { + out := test.kn.Run("trigger", "describe", name) + r.AssertNoError(out) + assert.Check(t, util.ContainsAllIgnoreCase(out.Stdout, filters...)) + assert.Check(t, util.ContainsAllIgnoreCase(out.Stdout, name, broker, sink)) } -func (test *e2eTest) verifyTriggerNotfound(t *testing.T, name string) { - _, err := test.kn.RunWithOpts([]string{"trigger", "describe", name}, runOpts{NoNamespace: false, AllowError: true}) - assert.ErrorContains(t, err, name, "not found") +func (test *e2eTest) verifyTriggerNotfound(t *testing.T, r *KnRunResultCollector, name string) { + out := test.kn.Run("trigger", "describe", name) + r.AssertError(out) + assert.Check(t, util.ContainsAll(out.Stderr, name, "not found")) } diff --git a/test/e2e/version_test.go b/test/e2e/version_test.go index b1dd2e5d2d..7921724e8d 100644 --- a/test/e2e/version_test.go +++ b/test/e2e/version_test.go @@ -25,10 +25,11 @@ import ( func TestVersion(t *testing.T) { t.Parallel() - env := buildEnv(t) - kn := kn{t, env.Namespace, Logger{}} - out, _ := kn.RunWithOpts([]string{"version"}, runOpts{NoNamespace: true}) + r := NewKnRunResultCollector(t) + defer r.DumpIfFailed() - assert.Check(t, util.ContainsAll(out, "Version")) + out := kn{}.Run("version") + r.AssertNoError(out) + assert.Check(t, util.ContainsAll(out.Stdout, "Version")) } diff --git a/vendor/contrib.go.opencensus.io/exporter/stackdriver/go.mod b/vendor/contrib.go.opencensus.io/exporter/stackdriver/go.mod index 12bcbace27..de12234109 100644 --- a/vendor/contrib.go.opencensus.io/exporter/stackdriver/go.mod +++ b/vendor/contrib.go.opencensus.io/exporter/stackdriver/go.mod @@ -6,21 +6,19 @@ require ( cloud.google.com/go v0.45.1 github.com/aws/aws-sdk-go v1.23.20 github.com/census-instrumentation/opencensus-proto v0.2.1 - github.com/davecgh/go-spew v1.1.1 // indirect github.com/golang/protobuf v1.3.2 github.com/google/go-cmp v0.3.1 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024 - github.com/stretchr/testify v1.3.0 // indirect + github.com/stretchr/testify v1.4.0 // indirect go.opencensus.io v0.22.1 golang.org/x/lint v0.0.0-20190409202823-959b441ac422 - golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2 + golang.org/x/net v0.0.0-20190923162816-aa69164e4478 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect - golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8 // indirect - golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0 + golang.org/x/tools v0.0.0-20191010075000-0337d82405ff google.golang.org/api v0.10.0 google.golang.org/appengine v1.6.2 // indirect google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51 google.golang.org/grpc v1.23.1 - honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc + honnef.co/go/tools v0.0.1-2019.2.3 ) diff --git a/vendor/contrib.go.opencensus.io/exporter/stackdriver/go.sum b/vendor/contrib.go.opencensus.io/exporter/stackdriver/go.sum index 5c5a219b81..382e63ca5f 100644 --- a/vendor/contrib.go.opencensus.io/exporter/stackdriver/go.sum +++ b/vendor/contrib.go.opencensus.io/exporter/stackdriver/go.sum @@ -20,8 +20,6 @@ github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -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/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I= @@ -46,6 +44,7 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/googleapis/gax-go/v2 v2.0.4 h1:hU4mGcQI4DaAYW+IbTun+2qEZVFxK0ySjQLTbS0VQKc= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= @@ -58,17 +57,25 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5i github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024 h1:rBMNdlhTLzJjJSDIjNEXX1Pz3Hmwmz91v+zycvx9PJc= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 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/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0 h1:C9hSCOW830chIVkdja34wa6Ky+IzWllkUinR+BtRZd4= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.1 h1:8dP3SGL7MPB94crU3bEPplMPe83FI4EouesJUeFHv50= go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -80,6 +87,7 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190409202823-959b441ac422 h1:QzoH/1pFpZguR8NrRHLcO6jKqfv2zpuSqZLgdm7ZmjI= golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -92,8 +100,8 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2 h1:4dVFTC832rPn4pomLSz1vA+are2+dU19w1H8OngV7nc= -golang.org/x/net v0.0.0-20190912160710-24e19bdeb0f2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g= +golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421 h1:Wo7BWFiOk0QRFMLYMqJGFMd9CgUAcGx7V+qEg/h5IBI= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -118,9 +126,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0 h1:HyfiK1WMnHj5FXFXatD+Qs1A/xC2Run6RzeW1SyHxpc= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8 h1:41hwlulw1prEMBxLQSlMSux1zxJf07B3WPsdjJlKZxE= -golang.org/x/sys v0.0.0-20190912141932-bc967efca4b8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To= @@ -139,8 +146,12 @@ golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0 h1:Dh6fw+p6FyRl5x/FvNswO1ji0lIGzm3KP8Y9VkS9PTE= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20191010075000-0337d82405ff h1:XdBG6es/oFDr1HwaxkxgVve7NB281QhxgK/i4voubFs= +golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.4.0 h1:KKgc1aqhV8wDPbDzlDtpvyjZFY3vjz85FP7p4wcQUyI= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0 h1:9sdfJOzWlkqPltHAuzT2Cp+yrBeY1KRVYgms8soxMwM= @@ -176,9 +187,17 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.1 h1:q4XQuHFC6I28BKZpo6IYyb3mNO+l7lSOxRuYTCiDfXk= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc h1:/hemPrYIhOhy8zYrNj+069zDB68us2sMGsfkFJO0iZs= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/vendor/contrib.go.opencensus.io/exporter/stackdriver/stackdriver.go b/vendor/contrib.go.opencensus.io/exporter/stackdriver/stackdriver.go index 1b13aaeb8c..32c858b675 100644 --- a/vendor/contrib.go.opencensus.io/exporter/stackdriver/stackdriver.go +++ b/vendor/contrib.go.opencensus.io/exporter/stackdriver/stackdriver.go @@ -429,6 +429,11 @@ func (e *Exporter) ExportSpan(sd *trace.SpanData) { e.traceExporter.ExportSpan(sd) } +// PushTraceSpans exports a bundle of OpenCensus Spans +func (e *Exporter) PushTraceSpans(ctx context.Context, node *commonpb.Node, rsc *resourcepb.Resource, spans []*trace.SpanData) (int, error) { + return len(spans), e.traceExporter.pushTraceSpans(ctx, node, rsc, spans) +} + func (e *Exporter) sdWithDefaultTraceAttributes(sd *trace.SpanData) *trace.SpanData { newSD := *sd newSD.Attributes = make(map[string]interface{}) diff --git a/vendor/contrib.go.opencensus.io/exporter/stackdriver/trace.go b/vendor/contrib.go.opencensus.io/exporter/stackdriver/trace.go index ae96986e36..2e09ed3c6f 100644 --- a/vendor/contrib.go.opencensus.io/exporter/stackdriver/trace.go +++ b/vendor/contrib.go.opencensus.io/exporter/stackdriver/trace.go @@ -26,6 +26,9 @@ import ( "go.opencensus.io/trace" "google.golang.org/api/support/bundler" tracepb "google.golang.org/genproto/googleapis/devtools/cloudtrace/v2" + + commonpb "github.com/census-instrumentation/opencensus-proto/gen-go/agent/common/v1" + resourcepb "github.com/census-instrumentation/opencensus-proto/gen-go/resource/v1" ) // traceExporter is an implementation of trace.Exporter that uploads spans to @@ -117,6 +120,37 @@ func (e *traceExporter) Flush() { e.bundler.Flush() } +func (e *traceExporter) pushTraceSpans(ctx context.Context, node *commonpb.Node, r *resourcepb.Resource, spans []*trace.SpanData) error { + ctx, span := trace.StartSpan( + ctx, + "contrib.go.opencensus.io/exporter/stackdriver.PushTraceSpans", + trace.WithSampler(trace.NeverSample()), + ) + defer span.End() + span.AddAttributes(trace.Int64Attribute("num_spans", int64(len(spans)))) + + protoSpans := make([]*tracepb.Span, 0, len(spans)) + + res := e.o.Resource + if r != nil { + res = e.o.MapResource(resourcepbToResource(r)) + } + + for _, span := range spans { + protoSpans = append(protoSpans, protoFromSpanData(span, e.projectID, res)) + } + + req := tracepb.BatchWriteSpansRequest{ + Name: "projects/" + e.projectID, + Spans: protoSpans, + } + // Create a never-sampled span to prevent traces associated with exporter. + ctx, cancel := newContextWithTimeout(ctx, e.o.Timeout) + defer cancel() + + return e.client.BatchWriteSpans(ctx, &req) +} + // uploadSpans uploads a set of spans to Stackdriver. func (e *traceExporter) uploadSpans(spans []*tracepb.Span) { req := tracepb.BatchWriteSpansRequest{ diff --git a/vendor/modules.txt b/vendor/modules.txt index ba84be7e9b..3a13617aa4 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -8,7 +8,7 @@ cloud.google.com/go/trace/apiv2 contrib.go.opencensus.io/exporter/ocagent # contrib.go.opencensus.io/exporter/prometheus v0.1.0 contrib.go.opencensus.io/exporter/prometheus -# contrib.go.opencensus.io/exporter/stackdriver v0.12.9 +# contrib.go.opencensus.io/exporter/stackdriver v0.13.0 contrib.go.opencensus.io/exporter/stackdriver contrib.go.opencensus.io/exporter/stackdriver/monitoredresource # github.com/PuerkitoBio/purell v1.1.1 @@ -106,7 +106,7 @@ github.com/google/go-cmp/cmp/internal/diff github.com/google/go-cmp/cmp/internal/flags github.com/google/go-cmp/cmp/internal/function github.com/google/go-cmp/cmp/internal/value -# github.com/google/go-containerregistry v0.0.0-20200131185320-aec8da010de2 +# github.com/google/go-containerregistry v0.0.0-20200212224832-c629a66d7231 github.com/google/go-containerregistry/pkg/name # github.com/google/gofuzz v1.0.0 github.com/google/gofuzz From 4a60831cc1532c53e98e60a7e1f38ec3a8d3c23c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Sat, 15 Feb 2020 12:46:59 +0100 Subject: [PATCH 2/3] chore(e2e): Add more dumpers --- test/e2e/cli.go | 53 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/test/e2e/cli.go b/test/e2e/cli.go index e3833e1eb7..b31d2de862 100644 --- a/test/e2e/cli.go +++ b/test/e2e/cli.go @@ -83,7 +83,7 @@ func (c *KnRunResultCollector) AssertError(result KnRunResult) { // AddDump adds extra dump information to the collector which is printed // out if an error occurs func (c *KnRunResultCollector) AddDump(kind string, name string, namespace string) { - dumpInfo := extractDumpInfo(kind, name, namespace) + dumpInfo := extractDumpInfoWithName(kind, name, namespace) if dumpInfo != "" { c.extraDumps = append(c.extraDumps, dumpInfo) } @@ -174,11 +174,7 @@ func RunKn(namespace string, args []string) KnRunResult { } if err != nil { command := args[0] - var name string - if len(args) > 2 { - name = args[2] - } - result.DumpInfo = extractDumpInfo(command, name, namespace) + result.DumpInfo = extractDumpInfo(command, args, namespace) } return result } @@ -208,27 +204,36 @@ func runCli(cli string, args []string) (string, string, error) { return stdout.String(), stderr.String(), err } -type dumpFunc func(name string, namespace string) string +type dumpFunc func(namespace string, args []string) string // Dump handler for specific commands ("service", "revision") which should add extra infos // Relies on that argv[1] is the command and argv[3] is the name of the object var dumpHandlers = map[string]dumpFunc{ - "service": dumpService, + "service": dumpService, + "revision": dumpRevision, + "route": dumpRoute, + "trigger": dumpTrigger, + // TODO: "source", +} + +func extractDumpInfoWithName(command string, name string, namespace string) string { + return extractDumpInfo(command, []string{command, "", name}, namespace) } -func extractDumpInfo(command, name string, namespace string) string { +func extractDumpInfo(command string, args []string, namespace string) string { dumpHandler := dumpHandlers[command] if dumpHandler != nil { - return dumpHandler(name, namespace) + return dumpHandler(namespace, args) } return "" } -func dumpService(name, namespace string) string { +func dumpService(namespace string, args []string) string { // For list like operation we don't have a name - if name == "" { + if len(args) < 3 || args[2] == "" { return "" } + name := args[2] var buffer bytes.Buffer // Service info @@ -244,6 +249,28 @@ func dumpService(name, namespace string) string { return buffer.String() } +func dumpRevision(namespace string, args []string) string { + return simpleDump("revision", args, namespace) +} + +func dumpRoute(namespace string, args []string) string { + return simpleDump("route", args, namespace) +} + +func dumpTrigger(namespace string, args []string) string { + return simpleDump("trigger", args, namespace) +} + +func simpleDump(kind string, args []string, namespace string) string { + if len(args) < 3 || args[2] == "" { + return "" + } + + var buffer bytes.Buffer + appendResourceInfo(&buffer, kind, args[2], namespace) + return buffer.String() +} + func appendResourceInfo(buffer *bytes.Buffer, kind string, name string, namespace string) { appendResourceInfoWithNameSelector(buffer, kind, name, namespace, "") } @@ -272,7 +299,7 @@ func appendResourceInfoWithNameSelector(buffer *bytes.Buffer, kind string, name } func appendCLIOutput(buffer *bytes.Buffer, desc string, out string, err error) { - buffer.WriteString(fmt.Sprintf("\n==== %s\n", desc)) + buffer.WriteString(fmt.Sprintf("==== %s\n", desc)) if err != nil { buffer.WriteString(fmt.Sprintf("%s: %v\n", "!!!! ERROR", err)) } From bb1946d4998e3e84f71c4c57dc3d51cee34a4470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Sat, 15 Feb 2020 22:19:31 +0100 Subject: [PATCH 3/3] Moar debug --- test/e2e/cli.go | 4 ++-- test/e2e/revision_test.go | 3 +++ test/e2e/traffic_split_test.go | 3 +++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/test/e2e/cli.go b/test/e2e/cli.go index b31d2de862..49645f02e7 100644 --- a/test/e2e/cli.go +++ b/test/e2e/cli.go @@ -30,8 +30,8 @@ type kn struct { } const ( - seperatorHeavy = "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - seperatorLight = "╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍" + seperatorHeavy = "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + seperatorLight = "╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍╍" ) // Run the 'kn' CLI with args and opts diff --git a/test/e2e/revision_test.go b/test/e2e/revision_test.go index 6d70006591..45a7a9ee36 100644 --- a/test/e2e/revision_test.go +++ b/test/e2e/revision_test.go @@ -84,6 +84,9 @@ func (test *e2eTest) revisionListWithService(t *testing.T, r *KnRunResultCollect assert.Check(t, util.ContainsAll(line, revName, svcName, strconv.Itoa(confGen))) confGen-- } + if t.Failed() { + r.AddDump("service", svcName, test.namespace) + } } } diff --git a/test/e2e/traffic_split_test.go b/test/e2e/traffic_split_test.go index a4f0c51dcc..fd4aab9ad2 100644 --- a/test/e2e/traffic_split_test.go +++ b/test/e2e/traffic_split_test.go @@ -420,6 +420,9 @@ func (test *e2eTest) verifyTargets(t *testing.T, r *KnRunResultCollector, servic assert.NilError(t, err) formattedActualTargets := formatActualTargets(t, actualTargets) assert.DeepEqual(t, expectedTargets, formattedActualTargets) + if t.Failed() { + r.AddDump("service", serviceName, test.namespace) + } } func (test *e2eTest) serviceDescribeWithJsonPath(r *KnRunResultCollector, serviceName, jsonpath string) string {