Skip to content
This repository has been archived by the owner on Jun 29, 2022. It is now read-only.

Commit

Permalink
test/ingress: refactor and fix bug
Browse files Browse the repository at this point in the history
This refactors the HTTP access code so it can be reused later for the
Headlamp ingress test.

It also fixes a bug where the Prometheus-Operator ingress wasn't being
tested because the "httpbin" string was hardcoded. It also introduces
the subpath as a test parameter because the "get" subpath doesn't exist
in the Prometheus ingress so it was failing.
  • Loading branch information
iaguis committed Oct 6, 2020
1 parent f9cc816 commit 86ccd2f
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 97 deletions.
103 changes: 6 additions & 97 deletions test/ingress/aws/aws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,41 +18,29 @@
package aws

import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"net/http"
"testing"
"time"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"

testutil "github.com/kinvolk/lokomotive/test/components/util"
)

const (
retryInterval = 5 * time.Second
retryTimeout = 9 * time.Minute
httpTimeout = 4 * time.Second
testingress "github.com/kinvolk/lokomotive/test/ingress"
)

func TestAWSIngress(t *testing.T) {
testCases := []struct {
Component string
Namespace string
Ingress string
Subpath string
}{
{
Component: "httpbin",
Namespace: "httpbin",
Ingress: "httpbin",
Subpath: "get",
},
{
Component: "prometheus-operator",
Namespace: "monitoring",
Ingress: "prometheus-operator-prometheus",
Subpath: "graph",
},
}

Expand All @@ -61,88 +49,9 @@ func TestAWSIngress(t *testing.T) {
t.Run(tc.Ingress, func(t *testing.T) {
t.Parallel()

client := testutil.CreateKubeClient(t)

i, err := client.NetworkingV1beta1().Ingresses("httpbin").Get(context.TODO(), "httpbin", metav1.GetOptions{})
if err != nil {
t.Fatalf("getting httpbin ingress: %v", err)
}

h := i.Spec.Rules[0].Host
c := getHTTPClient()

err = wait.PollImmediate(retryInterval, retryTimeout, func() (bool, error) {
resp, err := c.Get(fmt.Sprintf("https://%s/get", h))
if err != nil {
t.Logf("got an HTTP error: %v", err)
return false, nil
}

defer func() {
if err := resp.Body.Close(); err != nil {
t.Logf("closing HTTP response body: %v", err)
}
}()

if resp.StatusCode != http.StatusOK {
t.Logf("got a non-OK HTTP status: %d", resp.StatusCode)
return false, nil
}

return true, nil
})
if err != nil {
t.Fatal("could not get a successful HTTP response in time")
if err := testingress.AccessIngress(t, tc.Namespace, tc.Ingress, tc.Subpath); err != nil {
t.Fatalf("Accessing ingress %q: %v", tc.Ingress, err)
}
})
}
}

// getHTTPClient creates a HTTP client with LetsEncrypt Staging Root PEM certificate.
func getHTTPClient() *http.Client {
// Get this Root PEM from https://letsencrypt.org/docs/staging-environment/#root-certificate
letsEncryptStagingRootPEM := `-----BEGIN CERTIFICATE-----
MIIFATCCAumgAwIBAgIRAKc9ZKBASymy5TLOEp57N98wDQYJKoZIhvcNAQELBQAw
GjEYMBYGA1UEAwwPRmFrZSBMRSBSb290IFgxMB4XDTE2MDMyMzIyNTM0NloXDTM2
MDMyMzIyNTM0NlowGjEYMBYGA1UEAwwPRmFrZSBMRSBSb290IFgxMIICIjANBgkq
hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA+pYHvQw5iU3v2b3iNuYNKYgsWD6KU7aJ
diddtZQxSWYzUI3U0I1UsRPTxnhTifs/M9NW4ZlV13ZfB7APwC8oqKOIiwo7IwlP
xg0VKgyz+kT8RJfYr66PPIYP0fpTeu42LpMJ+CKo9sbpgVNDZN2z/qiXrRNX/VtG
TkPV7a44fZ5bHHVruAxvDnylpQxJobtCBWlJSsbIRGFHMc2z88eUz9NmIOWUKGGj
EmP76x8OfRHpIpuxRSCjn0+i9+hR2siIOpcMOGd+40uVJxbRRP5ZXnUFa2fF5FWd
O0u0RPI8HON0ovhrwPJY+4eWKkQzyC611oLPYGQ4EbifRsTsCxUZqyUuStGyp8oa
aoSKfF6X0+KzGgwwnrjRTUpIl19A92KR0Noo6h622OX+4sZiO/JQdkuX5w/HupK0
A0M0WSMCvU6GOhjGotmh2VTEJwHHY4+TUk0iQYRtv1crONklyZoAQPD76hCrC8Cr
IbgsZLfTMC8TWUoMbyUDgvgYkHKMoPm0VGVVuwpRKJxv7+2wXO+pivrrUl2Q9fPe
Kk055nJLMV9yPUdig8othUKrRfSxli946AEV1eEOhxddfEwBE3Lt2xn0hhiIedbb
Ftf/5kEWFZkXyUmMJK8Ra76Kus2ABueUVEcZ48hrRr1Hf1N9n59VbTUaXgeiZA50
qXf2bymE6F8CAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB
Af8wHQYDVR0OBBYEFMEmdKSKRKDm+iAo2FwjmkWIGHngMA0GCSqGSIb3DQEBCwUA
A4ICAQBCPw74M9X/Xx04K1VAES3ypgQYH5bf9FXVDrwhRFSVckria/7dMzoF5wln
uq9NGsjkkkDg17AohcQdr8alH4LvPdxpKr3BjpvEcmbqF8xH+MbbeUEnmbSfLI8H
sefuhXF9AF/9iYvpVNC8FmJ0OhiVv13VgMQw0CRKkbtjZBf8xaEhq/YqxWVsgOjm
dm5CAQ2X0aX7502x8wYRgMnZhA5goC1zVWBVAi8yhhmlhhoDUfg17cXkmaJC5pDd
oenZ9NVhW8eDb03MFCrWNvIh89DDeCGWuWfDltDq0n3owyL0IeSn7RfpSclpxVmV
/53jkYjwIgxIG7Gsv0LKMbsf6QdBcTjhvfZyMIpBRkTe3zuHd2feKzY9lEkbRvRQ
zbh4Ps5YBnG6CKJPTbe2hfi3nhnw/MyEmF3zb0hzvLWNrR9XW3ibb2oL3424XOwc
VjrTSCLzO9Rv6s5wi03qoWvKAQQAElqTYRHhynJ3w6wuvKYF5zcZF3MDnrVGLbh1
Q9ePRFBCiXOQ6wPLoUhrrbZ8LpFUFYDXHMtYM7P9sc9IAWoONXREJaO08zgFtMp4
8iyIYUyQAbsvx8oD2M8kRvrIRSrRJSl6L957b4AFiLIQ/GgV2curs0jje7Edx34c
idWw1VrejtwclobqNMVtG3EiPUIpJGpbMcJgbiLSmKkrvQtGng==
-----END CERTIFICATE-----`

rootCAs := x509.NewCertPool()
if ok := rootCAs.AppendCertsFromPEM([]byte(letsEncryptStagingRootPEM)); !ok {
// This should fail in the developer testing itself.
panic("Failed to parse root certificate")
}

return &http.Client{
Timeout: httpTimeout,
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: rootCAs,
},
},
}
}
134 changes: 134 additions & 0 deletions test/ingress/ingress.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Copyright 2020 The Lokomotive Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package ingress contains functions related to testing Ingress endpoints.
package ingress

import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"net/http"
"testing"
"time"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/wait"

testutil "github.com/kinvolk/lokomotive/test/components/util"
)

const (
retryInterval = 5 * time.Second
retryTimeout = 9 * time.Minute
httpTimeout = 4 * time.Second
)

// getHTTPClient creates a HTTP client with LetsEncrypt Staging Root PEM certificate.
func getHTTPClient(timeout time.Duration) *http.Client {
// Get this Root PEM from https://letsencrypt.org/docs/staging-environment/#root-certificate
letsEncryptStagingRootPEM := `-----BEGIN CERTIFICATE-----
MIIFATCCAumgAwIBAgIRAKc9ZKBASymy5TLOEp57N98wDQYJKoZIhvcNAQELBQAw
GjEYMBYGA1UEAwwPRmFrZSBMRSBSb290IFgxMB4XDTE2MDMyMzIyNTM0NloXDTM2
MDMyMzIyNTM0NlowGjEYMBYGA1UEAwwPRmFrZSBMRSBSb290IFgxMIICIjANBgkq
hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA+pYHvQw5iU3v2b3iNuYNKYgsWD6KU7aJ
diddtZQxSWYzUI3U0I1UsRPTxnhTifs/M9NW4ZlV13ZfB7APwC8oqKOIiwo7IwlP
xg0VKgyz+kT8RJfYr66PPIYP0fpTeu42LpMJ+CKo9sbpgVNDZN2z/qiXrRNX/VtG
TkPV7a44fZ5bHHVruAxvDnylpQxJobtCBWlJSsbIRGFHMc2z88eUz9NmIOWUKGGj
EmP76x8OfRHpIpuxRSCjn0+i9+hR2siIOpcMOGd+40uVJxbRRP5ZXnUFa2fF5FWd
O0u0RPI8HON0ovhrwPJY+4eWKkQzyC611oLPYGQ4EbifRsTsCxUZqyUuStGyp8oa
aoSKfF6X0+KzGgwwnrjRTUpIl19A92KR0Noo6h622OX+4sZiO/JQdkuX5w/HupK0
A0M0WSMCvU6GOhjGotmh2VTEJwHHY4+TUk0iQYRtv1crONklyZoAQPD76hCrC8Cr
IbgsZLfTMC8TWUoMbyUDgvgYkHKMoPm0VGVVuwpRKJxv7+2wXO+pivrrUl2Q9fPe
Kk055nJLMV9yPUdig8othUKrRfSxli946AEV1eEOhxddfEwBE3Lt2xn0hhiIedbb
Ftf/5kEWFZkXyUmMJK8Ra76Kus2ABueUVEcZ48hrRr1Hf1N9n59VbTUaXgeiZA50
qXf2bymE6F8CAwEAAaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB
Af8wHQYDVR0OBBYEFMEmdKSKRKDm+iAo2FwjmkWIGHngMA0GCSqGSIb3DQEBCwUA
A4ICAQBCPw74M9X/Xx04K1VAES3ypgQYH5bf9FXVDrwhRFSVckria/7dMzoF5wln
uq9NGsjkkkDg17AohcQdr8alH4LvPdxpKr3BjpvEcmbqF8xH+MbbeUEnmbSfLI8H
sefuhXF9AF/9iYvpVNC8FmJ0OhiVv13VgMQw0CRKkbtjZBf8xaEhq/YqxWVsgOjm
dm5CAQ2X0aX7502x8wYRgMnZhA5goC1zVWBVAi8yhhmlhhoDUfg17cXkmaJC5pDd
oenZ9NVhW8eDb03MFCrWNvIh89DDeCGWuWfDltDq0n3owyL0IeSn7RfpSclpxVmV
/53jkYjwIgxIG7Gsv0LKMbsf6QdBcTjhvfZyMIpBRkTe3zuHd2feKzY9lEkbRvRQ
zbh4Ps5YBnG6CKJPTbe2hfi3nhnw/MyEmF3zb0hzvLWNrR9XW3ibb2oL3424XOwc
VjrTSCLzO9Rv6s5wi03qoWvKAQQAElqTYRHhynJ3w6wuvKYF5zcZF3MDnrVGLbh1
Q9ePRFBCiXOQ6wPLoUhrrbZ8LpFUFYDXHMtYM7P9sc9IAWoONXREJaO08zgFtMp4
8iyIYUyQAbsvx8oD2M8kRvrIRSrRJSl6L957b4AFiLIQ/GgV2curs0jje7Edx34c
idWw1VrejtwclobqNMVtG3EiPUIpJGpbMcJgbiLSmKkrvQtGng==
-----END CERTIFICATE-----`

rootCAs := x509.NewCertPool()
if ok := rootCAs.AppendCertsFromPEM([]byte(letsEncryptStagingRootPEM)); !ok {
// This should fail in the developer testing itself.
panic("Failed to parse root certificate")
}

return &http.Client{
Timeout: timeout,
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
RootCAs: rootCAs,
},
},
}
}

// AccessIngress access the first host of Ingress name in namespace in subPath
// expecting an http StatusOK. Otherwise it returns an error.
func AccessIngress(t *testing.T, namespace, name, subPath string) error {
client := testutil.CreateKubeClient(t)

i, err := client.NetworkingV1beta1().Ingresses(namespace).Get(context.TODO(), name, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("getting httpbin ingress: %w", err)
}

h := i.Spec.Rules[0].Host
c := getHTTPClient(httpTimeout)

err = wait.PollImmediate(retryInterval, retryTimeout, func() (bool, error) {
req, err := http.NewRequestWithContext(context.TODO(), "GET", (fmt.Sprintf("https://%s/%s", h, subPath)), nil)
if err != nil {
return false, fmt.Errorf("creating GET request: %w", err)
}

resp, err := c.Do(req)
if err != nil {
t.Logf("got an HTTP error: %v", err)

return false, nil
}

defer func() {
if err := resp.Body.Close(); err != nil {
t.Logf("closing HTTP response body: %v", err)
}
}()

if resp.StatusCode != http.StatusOK {
t.Logf("got a non-OK HTTP status: %d", resp.StatusCode)

return false, nil
}

return true, nil
})
if err != nil {
return err
}

return nil
}

0 comments on commit 86ccd2f

Please sign in to comment.