Skip to content

Commit

Permalink
Merge pull request #61 from akshaymankar/integration-tests
Browse files Browse the repository at this point in the history
Add Integration tests
  • Loading branch information
k8s-ci-robot authored Sep 1, 2020
2 parents 779d619 + ecff4d3 commit 1820c33
Show file tree
Hide file tree
Showing 12 changed files with 461 additions and 78 deletions.
133 changes: 55 additions & 78 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,17 @@
# Do not choose a language; we provide our own build tools.
language: generic

services:
- docker

# Caching so the next build will be fast too.
cache:
directories:
- $HOME/.ghc
- $HOME/.cabal
- $HOME/.stack
- $TRAVIS_BUILD_DIR/.stack-work
- $TRAVIS_BUILD_DIR/examples/.stack-work

# The different configurations we want to test. We have BUILD=cabal which uses
# cabal-install, and BUILD=stack which uses Stack. More documentation on each
Expand All @@ -31,38 +35,26 @@ cache:
# addons: {apt: {packages: [libfcgi-dev,libgmp-dev]}}
matrix:
include:
# We grab the appropriate GHC and cabal-install versions from hvr's PPA. See:
# https://github.com/hvr/multi-ghc-travis
#- env: BUILD=cabal GHCVER=7.0.4 CABALVER=1.16 HAPPYVER=1.19.5 ALEXVER=3.1.7
# compiler: ": #GHC 7.0.4"
# addons: {apt: {packages: [cabal-install-1.16,ghc-7.0.4,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
#- env: BUILD=cabal GHCVER=7.2.2 CABALVER=1.16 HAPPYVER=1.19.5 ALEXVER=3.1.7
# compiler: ": #GHC 7.2.2"
# addons: {apt: {packages: [cabal-install-1.16,ghc-7.2.2,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
#- env: BUILD=cabal GHCVER=7.4.2 CABALVER=1.16 HAPPYVER=1.19.5 ALEXVER=3.1.7
# compiler: ": #GHC 7.4.2"
# addons: {apt: {packages: [cabal-install-1.16,ghc-7.4.2,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
#- env: BUILD=cabal GHCVER=7.6.3 CABALVER=1.16 HAPPYVER=1.19.5 ALEXVER=3.1.7
# compiler: ": #GHC 7.6.3"
# addons: {apt: {packages: [cabal-install-1.16,ghc-7.6.3,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
#- env: BUILD=cabal GHCVER=7.8.4 CABALVER=1.18 HAPPYVER=1.19.5 ALEXVER=3.1.7
# compiler: ": #GHC 7.8.4"
# addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
#- env: BUILD=cabal GHCVER=7.10.3 CABALVER=1.22 HAPPYVER=1.19.5 ALEXVER=3.1.7
# compiler: ": #GHC 7.10.3"
# addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
- env: BUILD=cabal GHCVER=8.0.2 CABALVER=1.24 HAPPYVER=1.19.5 ALEXVER=3.1.7
compiler: ": #GHC 8.0.2"
addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.2,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
- env: BUILD=integration-tests
compiler: ": #integration-tests"
addons: {apt: {packages: [libgmp-dev]}}

- env: BUILD=stack ARGS=""
compiler: ": #stack default"
addons: {apt: {packages: [libgmp-dev]}}

# - env: BUILD=cabal GHCVER=8.0.2 CABALVER=1.24 HAPPYVER=1.19.5 ALEXVER=3.1.7
# compiler: ": #GHC 8.0.2"
# addons: {apt: {packages: [cabal-install-1.24,ghc-8.0.2,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
- env: BUILD=cabal GHCVER=8.2.2 CABALVER=2.0 HAPPYVER=1.19.5 ALEXVER=3.1.7
compiler: ": #GHC 8.2.2"
addons: {apt: {packages: [cabal-install-2.0,ghc-8.2.2,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
- env: BUILD=cabal GHCVER=8.4.4 CABALVER=2.2 HAPPYVER=1.19.5 ALEXVER=3.1.7
compiler: ": #GHC 8.4.4"
addons: {apt: {packages: [cabal-install-2.2,ghc-8.4.4,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
- env: BUILD=cabal GHCVER=8.6.3 CABALVER=2.4 HAPPYVER=1.19.5 ALEXVER=3.1.7
compiler: ": #GHC 8.6.3"
addons: {apt: {packages: [cabal-install-2.4,ghc-8.6.3,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}
- env: BUILD=cabal GHCVER=8.6.5 CABALVER=2.4 HAPPYVER=1.19.5 ALEXVER=3.1.7
compiler: ": #GHC 8.6.5"
addons: {apt: {packages: [cabal-install-2.4,ghc-8.6.5,happy-1.19.5,alex-3.1.7], sources: [hvr-ghc]}}

# Build with the newest GHC and cabal-install. This is an accepted failure,
# see below.
Expand All @@ -72,30 +64,6 @@ matrix:

# The Stack builds. We can pass in arbitrary Stack arguments via the ARGS
# variable, such as using --stack-yaml to point to a different file.
- env: BUILD=stack ARGS=""
compiler: ": #stack default"
addons: {apt: {packages: [libgmp-dev]}}

#- env: BUILD=stack ARGS="--resolver lts-2"
# compiler: ": #stack 7.8.4"
# addons: {apt: {packages: [libgmp-dev]}}

#- env: BUILD=stack ARGS="--resolver lts-3"
# compiler: ": #stack 7.10.2"
# addons: {apt: {packages: [libgmp-dev]}}

#- env: BUILD=stack ARGS="--resolver lts-6"
# compiler: ": #stack 7.10.3"
# addons: {apt: {packages: [libgmp-dev]}}

#- env: BUILD=stack ARGS="--resolver lts-7"
# compiler: ": #stack 8.0.1"
# addons: {apt: {packages: [libgmp-dev]}}

#- env: BUILD=stack ARGS="--resolver lts-9"
# compiler: ": #stack 8.0.2"
# addons: {apt: {packages: [libgmp-dev]}}

- env: BUILD=stack ARGS="--resolver lts-11 --stack-yaml stack-8.2.2.yaml"
compiler: ": #stack 8.2.2"
addons: {apt: {packages: [libgmp-dev]}}
Expand All @@ -104,8 +72,8 @@ matrix:
compiler: ": #stack 8.4.4"
addons: {apt: {packages: [libgmp-dev]}}

- env: BUILD=stack ARGS="--resolver lts-13"
compiler: ": #stack 8.6.3"
- env: BUILD=stack ARGS="--resolver lts-14"
compiler: ": #stack 8.6.5"
addons: {apt: {packages: [libgmp-dev]}}

# Nightly builds are allowed to fail
Expand All @@ -118,27 +86,6 @@ matrix:
compiler: ": #stack default osx"
os: osx

# Travis includes an macOS which is incompatible with GHC 7.8.4
#- env: BUILD=stack ARGS="--resolver lts-2"
# compiler: ": #stack 7.8.4 osx"
# os: osx

#- env: BUILD=stack ARGS="--resolver lts-3"
# compiler: ": #stack 7.10.2 osx"
# os: osx

#- env: BUILD=stack ARGS="--resolver lts-6"
# compiler: ": #stack 7.10.3 osx"
# os: osx

#- env: BUILD=stack ARGS="--resolver lts-7"
# compiler: ": #stack 8.0.1 osx"
# os: osx

#- env: BUILD=stack ARGS="--resolver lts-9"
# compiler: ": #stack 8.0.2 osx"
# os: osx

- env: BUILD=stack ARGS="--resolver lts-11 --stack-yaml stack-8.2.2.yaml"
compiler: ": #stack 8.2.2 osx"
os: osx
Expand All @@ -147,8 +94,8 @@ matrix:
compiler: ": #stack 8.4.4 osx"
os: osx

- env: BUILD=stack ARGS="--resolver lts-13"
compiler: ": #stack 8.6.3 osx"
- env: BUILD=stack ARGS="--resolver lts-14"
compiler: ": #stack 8.6.5 osx"
os: osx

- env: BUILD=stack ARGS="--resolver nightly"
Expand Down Expand Up @@ -202,7 +149,7 @@ install:
# stack --no-terminal $ARGS solver --update-config)
# Build the dependencies
stack --no-terminal --install-ghc $ARGS test --bench --only-dependencies
stack --no-terminal --install-ghc $ARGS test --bench --only-dependencies --fast
;;
cabal)
cabal --version
Expand All @@ -211,10 +158,22 @@ install:
# Get the list of packages from the stack.yaml file. Note that
# this will also implicitly run hpack as necessary to generate
# the .cabal files needed by cabal-install.
PACKAGES=$(stack --install-ghc query locals | grep '^ *path' | sed 's@^ *path:@@')
PACKAGES=$(stack --system-ghc query locals | grep '^ *path' | sed 's@^ *path:@@')
cabal install --only-dependencies --enable-tests --enable-benchmarks --force-reinstalls --ghc-options=-O0 --reorder-goals --max-backjumps=-1 $CABALARGS $PACKAGES
;;
integration-tests)
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && chmod +x kubectl && sudo mv kubectl /usr/local/bin/
# Download and install kind
curl -LO https://github.com/kubernetes-sigs/kind/releases/download/v0.5.1/kind-linux-amd64 && chmod +x kind-linux-amd64 && sudo mv kind-linux-amd64 /usr/local/bin/kind
# Create a new Kubernetes cluster using KinD
kind create cluster
# Set KUBECONFIG environment variable
export KUBECONFIG="$(kind get kubeconfig-path)"
stack --no-terminal --install-ghc --stack-yaml ./examples/stack.yaml --work-dir .stack-work build --only-dependencies --fast
;;
esac
set +ex
Expand All @@ -223,7 +182,7 @@ script:
set -ex
case "$BUILD" in
stack)
stack --no-terminal $ARGS test --bench --no-run-benchmarks --haddock --no-haddock-deps
stack --no-terminal $ARGS test --bench --no-run-benchmarks --haddock --no-haddock-deps --fast
;;
cabal)
cabal install --enable-tests --enable-benchmarks --force-reinstalls --ghc-options=-O0 --reorder-goals --max-backjumps=-1 $CABALARGS $PACKAGES
Expand All @@ -249,5 +208,23 @@ script:
cd $ORIGDIR
done
;;
integration-tests)
EXAMPLE_ARGS="--no-terminal --install-ghc --stack-yaml ./examples/stack.yaml --work-dir .stack-work"
stack $EXAMPLE_ARGS build --fast
# Run simple test
stack $EXAMPLE_ARGS exec simple
# Build and load the in-cluster-example image
cp "$(stack $EXAMPLE_ARGS exec which in-cluster)" in-cluster-example
docker build . -f ./examples/in-cluster/Dockerfile -t in-cluster-example:latest
kind load docker-image in-cluster-example:latest
# Wait for kind node to be ready
kubectl wait --for=condition=Ready node --all
# Run the test pod
./examples/in-cluster/run-test.sh
;;
esac
set +ex
4 changes: 4 additions & 0 deletions examples/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dist
dist-newstyle
*.cabal
.stack-work
1 change: 1 addition & 0 deletions examples/LICENSE
5 changes: 5 additions & 0 deletions examples/in-cluster/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
FROM ubuntu:xenial

RUN apt-get update && apt-get install -y libgmp3-dev

COPY in-cluster-example /usr/local/bin
85 changes: 85 additions & 0 deletions examples/in-cluster/Main.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
{-# LANGUAGE OverloadedStrings #-}
module Main where

import Control.Concurrent.STM
import Control.Exception.Safe
import Kubernetes.Client
import Kubernetes.OpenAPI
import Kubernetes.OpenAPI.API.CoreV1
import Network.HTTP.Client
import Network.HTTP.Types.Status

import qualified Data.Map as Map
import qualified Data.Text as T
import qualified Data.Text.IO as T

main :: IO ()
main = do
oidcCache <- newTVarIO $ Map.fromList []
(manager, cfg) <- mkKubeClientConfig oidcCache KubeConfigCluster
let createNamespaceRequest =
createNamespace (ContentType MimeJSON) (Accept MimeJSON) testNamespace
createdNS <- assertMimeSuccess =<< dispatchMime manager cfg createNamespaceRequest
nsName <- assertJust "Expected K8s to generate name for namespace, but it didn't"
$ (v1ObjectMetaName =<< v1NamespaceMetadata createdNS)
T.putStrLn $ "Created Namespace: " <> nsName

-- NOTE: We cannot use dispatchMime due to this issue: https://github.com/kubernetes/kubernetes/issues/59501
let deleteNamespaceRequest =
deleteNamespace (ContentType MimeJSON) (Accept MimeJSON) (Name nsName)
deleteNamespaceResponse <- dispatchLbs manager cfg deleteNamespaceRequest
if responseStatus deleteNamespaceResponse /= status200
then throwM $ AssertionFailure
$ "Failed to cleanup namespace: " <> T.unpack nsName
<> "\nStatus Code: " <> show (responseStatus deleteNamespaceResponse)
<> "\nBody: " <> show (responseBody deleteNamespaceResponse)
else return ()
putStrLn "Clenaup complete!"

testDeployment :: V1Deployment
testDeployment =
let labelSelector =
mkV1LabelSelector
{ v1LabelSelectorMatchLabels =
Just $ Map.fromList [("app", "test")] }
container =
(mkV1Container "container-name")
{ v1ContainerImage = Just $ "nginx" }
podTemplate =
mkV1PodTemplateSpec
{ v1PodTemplateSpecMetadata =
Just $ mkV1ObjectMeta
{ v1ObjectMetaLabels = Just $ Map.fromList [("app", "test")] }
, v1PodTemplateSpecSpec =
Just $
mkV1PodSpec [container]
}
in mkV1Deployment
{ v1DeploymentMetadata =
Just $ mkV1ObjectMeta { v1ObjectMetaName = Just "test-deployment" }
, v1DeploymentSpec =
Just
$ (mkV1DeploymentSpec labelSelector podTemplate)
}

testNamespace :: V1Namespace
testNamespace =
let nsMetadata =
mkV1ObjectMeta
{ v1ObjectMetaGenerateName = Just "haskell-client-test-" }
in mkV1Namespace
{ v1NamespaceMetadata = Just nsMetadata }

assertMimeSuccess :: MonadThrow m => MimeResult a -> m a
assertMimeSuccess (MimeResult (Right res) _) = pure res
assertMimeSuccess (MimeResult (Left err) _) =
throwM $ AssertionFailure $ "Unexpected MimeError: " ++ show err

assertJust :: MonadThrow m => String -> Maybe a -> m a
assertJust err Nothing = throwM $ AssertionFailure err
assertJust _ (Just x) = return x

data AssertionFailure = AssertionFailure String
deriving Show

instance Exception AssertionFailure
68 changes: 68 additions & 0 deletions examples/in-cluster/run-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/bin/bash

set -euo pipefail

SCRIPT_DIR="$( cd "$(dirname "$0")" ; pwd -P )"
MAX_SECONDS=20

main(){
kubectl apply -f "$SCRIPT_DIR/test-pod.yaml"
start_time="$(date +%s)"
while true; do
phase="$(get-pod-phase in-cluster-example)"
consumed_seconds="$(seconds-since $start_time)"

if [[ "$phase" == "Succeeded" ]]; then
echo "------------------------------"
echo "Test passed!"
echo "------------------------------"
echo
echo "------------------------------"
echo "Logs from test:"
echo "------------------------------"
kubectl logs in-cluster-example
exit 0
elif [[ "$phase" == "Failed" ]]; then
echo "------------------------------"
echo "Test failed!"
echo "------------------------------"
print-failure in-cluster-example
exit 1
elif (( consumed_seconds > MAX_SECONDS )); then
echo "------------------------------"
echo "Test timed out after $MAX_SECONDS seconds!"
echo "------------------------------"
print-failure in-cluster-example
exit 2
else
echo "Test still running, pod phase = $phase"
sleep 0.5
fi
done
}

get-pod-phase() {
kubectl get pod $1 -o 'jsonpath={.status.phase}'
}

print-failure() {
echo
echo "------------------------------"
echo "Pod Description:"
echo "------------------------------"
kubectl describe pod $1
echo
echo "------------------------------"
echo "Logs from test:"
echo "------------------------------"
kubectl logs $1
}

# Takes epoch time
seconds-since() {
local start=$1
local end=$(date +%s)
echo $(( end - start))
}

main
Loading

0 comments on commit 1820c33

Please sign in to comment.