Skip to content

Commit

Permalink
Merge pull request #749 from pivotal-k8s/move-testing-framework-squash
Browse files Browse the repository at this point in the history
⚠ Bring in testing framework
  • Loading branch information
k8s-ci-robot authored Jan 6, 2020
2 parents efbeb27 + c53fbe1 commit a4043d2
Show file tree
Hide file tree
Showing 36 changed files with 1,929 additions and 8 deletions.
4 changes: 4 additions & 0 deletions OWNERS_ALIASES
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ aliases:
- shawn-hurley
- gerred
- joelanford
testing-integration-admins:
- apelisse
- hoegaarden
- totherme
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,5 @@ require (
k8s.io/apimachinery v0.0.0-20190913080033-27d36303b655
k8s.io/client-go v0.0.0-20190918160344-1fbdaa4c8d90
k8s.io/utils v0.0.0-20190801114015-581e00157fb1
sigs.k8s.io/testing_frameworks v0.1.2
sigs.k8s.io/yaml v1.1.0
)
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,5 @@ modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs
modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
sigs.k8s.io/structured-merge-diff v0.0.0-20190817042607-6149e4549fca/go.mod h1:IIgPezJWb76P0hotTxzDbWsMYB8APh18qZnxkomBpxA=
sigs.k8s.io/testing_frameworks v0.1.2 h1:vK0+tvjF0BZ/RYFeZ1E6BYBwHJJXhjuZ3TdsEKH+UQM=
sigs.k8s.io/testing_frameworks v0.1.2/go.mod h1:ToQrwSC3s8Xf/lADdZp3Mktcql9CG0UAmdJG9th5i0w=
sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
11 changes: 8 additions & 3 deletions hack/check-everything.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,19 @@ SKIP_FETCH_TOOLS=${SKIP_FETCH_TOOLS:-""}

# fetch k8s API gen tools and make it available under kb_root_dir/bin.
function fetch_kb_tools {
header_text "fetching tools"
local dest_dir="${1}"

header_text "fetching tools (into '${dest_dir}')"
kb_tools_archive_name="kubebuilder-tools-$k8s_version-$goos-$goarch.tar.gz"
kb_tools_download_url="https://storage.googleapis.com/kubebuilder-tools/$kb_tools_archive_name"

kb_tools_archive_path="$tmp_root/$kb_tools_archive_name"
if [ ! -f $kb_tools_archive_path ]; then
curl -sL ${kb_tools_download_url} -o "$kb_tools_archive_path"
fi
tar -zvxf "$kb_tools_archive_path" -C "$tmp_root/"

mkdir -p "${dest_dir}"
tar -C "${dest_dir}" --strip-components=1 -zvxf "$kb_tools_archive_path"
}

function is_installed {
Expand All @@ -78,7 +82,8 @@ header_text "using tools"

if [ -z "$SKIP_FETCH_TOOLS" ]; then
fetch_go_tools
fetch_kb_tools
fetch_kb_tools "$kb_root_dir"
fetch_kb_tools "${hack_dir}/../pkg/internal/testing/integration/assets"
fi

setup_envs
Expand Down
2 changes: 1 addition & 1 deletion pkg/builder/builder_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/envtest"
"sigs.k8s.io/controller-runtime/pkg/internal/testing/integration/addr"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"sigs.k8s.io/controller-runtime/pkg/metrics"
"sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/testing_frameworks/integration/addr"
)

func TestBuilder(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/envtest/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client/config"
"sigs.k8s.io/testing_frameworks/integration"
"sigs.k8s.io/controller-runtime/pkg/internal/testing/integration"

logf "sigs.k8s.io/controller-runtime/pkg/internal/log"
)
Expand Down
5 changes: 5 additions & 0 deletions pkg/internal/testing/OWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# See the OWNERS docs: https://git.k8s.io/community/contributors/devel/owners.md

approvers:
- controller-runtime-admins
- testing-integration-admins
1 change: 1 addition & 0 deletions pkg/internal/testing/integration/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
assets/bin
10 changes: 10 additions & 0 deletions pkg/internal/testing/integration/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Integration Testing Framework

This package has been moved from [https://github.com/kubernetes-sigs/testing_frameworks/tree/master/integration](https://github.com/kubernetes-sigs/testing_frameworks/tree/master/integration).

A framework for integration testing components of kubernetes. This framework is
intended to work properly both in CI, and on a local dev machine. It therefore
explicitly supports both Linux and Darwin.

For detailed documentation see the
[![GoDoc](https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/internal/testing/integration?status.svg)](https://godoc.org/github.com/kubernetes-sigs/controller-runtime/pkg/internal/testing/integration).
14 changes: 14 additions & 0 deletions pkg/internal/testing/integration/addr/addr_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package addr_test

import (
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"

"testing"
)

func TestAddr(t *testing.T) {
t.Parallel()
RegisterFailHandler(Fail)
RunSpecs(t, "Addr Suite")
}
74 changes: 74 additions & 0 deletions pkg/internal/testing/integration/addr/manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package addr

import (
"fmt"
"net"
"sync"
"time"
)

const (
portReserveTime = 1 * time.Minute
portConflictRetry = 100
)

type portCache struct {
lock sync.Mutex
ports map[int]time.Time
}

func (c *portCache) add(port int) bool {
c.lock.Lock()
defer c.lock.Unlock()
// remove outdated port
for p, t := range c.ports {
if time.Since(t) > portReserveTime {
delete(c.ports, p)
}
}
// try allocating new port
if _, ok := c.ports[port]; ok {
return false
}
c.ports[port] = time.Now()
return true
}

var cache = &portCache{
ports: make(map[int]time.Time),
}

func suggest() (port int, resolvedHost string, err error) {
addr, err := net.ResolveTCPAddr("tcp", "localhost:0")
if err != nil {
return
}
l, err := net.ListenTCP("tcp", addr)
if err != nil {
return
}
port = l.Addr().(*net.TCPAddr).Port
defer func() {
err = l.Close()
}()
resolvedHost = addr.IP.String()
return
}

// Suggest suggests an address a process can listen on. It returns
// a tuple consisting of a free port and the hostname resolved to its IP.
// It makes sure that new port allocated does not conflict with old ports
// allocated within 1 minute.
func Suggest() (port int, resolvedHost string, err error) {
for i := 0; i < portConflictRetry; i++ {
port, resolvedHost, err = suggest()
if err != nil {
return
}
if cache.add(port) {
return
}
}
err = fmt.Errorf("no free ports found after %d retries", portConflictRetry)
return
}
29 changes: 29 additions & 0 deletions pkg/internal/testing/integration/addr/manager_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package addr_test

import (
"sigs.k8s.io/controller-runtime/pkg/internal/testing/integration/addr"

"net"
"strconv"

. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)

var _ = Describe("SuggestAddress", func() {
It("returns a free port and an address to bind to", func() {
port, host, err := addr.Suggest()

Expect(err).NotTo(HaveOccurred())
Expect(host).To(Or(Equal("127.0.0.1"), Equal("::1")))
Expect(port).NotTo(Equal(0))

addr, err := net.ResolveTCPAddr("tcp", net.JoinHostPort(host, strconv.Itoa(port)))
Expect(err).NotTo(HaveOccurred())
l, err := net.ListenTCP("tcp", addr)
defer func() {
Expect(l.Close()).To(Succeed())
}()
Expect(err).NotTo(HaveOccurred())
})
})
136 changes: 136 additions & 0 deletions pkg/internal/testing/integration/apiserver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package integration

import (
"fmt"
"io"
"net/url"
"time"

"sigs.k8s.io/controller-runtime/pkg/internal/testing/integration/addr"
"sigs.k8s.io/controller-runtime/pkg/internal/testing/integration/internal"
)

// APIServer knows how to run a kubernetes apiserver.
type APIServer struct {
// URL is the address the ApiServer should listen on for client connections.
//
// If this is not specified, we default to a random free port on localhost.
URL *url.URL

// SecurePort is the additional secure port that the APIServer should listen on.
SecurePort int

// Path is the path to the apiserver binary.
//
// If this is left as the empty string, we will attempt to locate a binary,
// by checking for the TEST_ASSET_KUBE_APISERVER environment variable, and
// the default test assets directory. See the "Binaries" section above (in
// doc.go) for details.
Path string

// Args is a list of arguments which will passed to the APIServer binary.
// Before they are passed on, they will be evaluated as go-template strings.
// This means you can use fields which are defined and exported on this
// APIServer struct (e.g. "--cert-dir={{ .Dir }}").
// Those templates will be evaluated after the defaulting of the APIServer's
// fields has already happened and just before the binary actually gets
// started. Thus you have access to calculated fields like `URL` and others.
//
// If not specified, the minimal set of arguments to run the APIServer will
// be used.
Args []string

// CertDir is a path to a directory containing whatever certificates the
// APIServer will need.
//
// If left unspecified, then the Start() method will create a fresh temporary
// directory, and the Stop() method will clean it up.
CertDir string

// EtcdURL is the URL of the Etcd the APIServer should use.
//
// If this is not specified, the Start() method will return an error.
EtcdURL *url.URL

// StartTimeout, StopTimeout specify the time the APIServer is allowed to
// take when starting and stoppping before an error is emitted.
//
// If not specified, these default to 20 seconds.
StartTimeout time.Duration
StopTimeout time.Duration

// Out, Err specify where APIServer should write its StdOut, StdErr to.
//
// If not specified, the output will be discarded.
Out io.Writer
Err io.Writer

processState *internal.ProcessState
}

// Start starts the apiserver, waits for it to come up, and returns an error,
// if occurred.
func (s *APIServer) Start() error {
if s.processState == nil {
if err := s.setProcessState(); err != nil {
return err
}
}
return s.processState.Start(s.Out, s.Err)
}

func (s *APIServer) setProcessState() error {
if s.EtcdURL == nil {
return fmt.Errorf("expected EtcdURL to be configured")
}

var err error

s.processState = &internal.ProcessState{}

s.processState.DefaultedProcessInput, err = internal.DoDefaulting(
"kube-apiserver",
s.URL,
s.CertDir,
s.Path,
s.StartTimeout,
s.StopTimeout,
)
if err != nil {
return err
}

// Defaulting the secure port
if s.SecurePort == 0 {
s.SecurePort, _, err = addr.Suggest()
if err != nil {
return err
}
}

s.processState.HealthCheckEndpoint = "/healthz"

s.URL = &s.processState.URL
s.CertDir = s.processState.Dir
s.Path = s.processState.Path
s.StartTimeout = s.processState.StartTimeout
s.StopTimeout = s.processState.StopTimeout

s.processState.Args, err = internal.RenderTemplates(
internal.DoAPIServerArgDefaulting(s.Args), s,
)
return err
}

// Stop stops this process gracefully, waits for its termination, and cleans up
// the CertDir if necessary.
func (s *APIServer) Stop() error {
return s.processState.Stop()
}

// APIServerDefaultArgs exposes the default args for the APIServer so that you
// can use those to append your own additional arguments.
//
// The internal default arguments are explicitly copied here, we don't want to
// allow users to change the internal ones.
var APIServerDefaultArgs = append([]string{}, internal.APIServerDefaultArgs...)
1 change: 1 addition & 0 deletions pkg/internal/testing/integration/assets/bin/.gitkeep
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This directory will be the home of some binaries which are downloaded with `pkg/framework/test/scripts/download-binaries`.
Loading

0 comments on commit a4043d2

Please sign in to comment.