Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 177 additions & 0 deletions .github/workflows/qe-minikube.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
---
name: QE Testing (Minikube)

on:
pull_request:
branches: [ main ]
paths:
- 'tests/**'
- 'go.mod'
- 'go.sum'
- '.github/workflows/qe-ocp.yml'
- '.github/workflows/qe-minikube.yml'
workflow_dispatch:
# Schedule a daily cron at midnight UTC
schedule:
- cron: '0 0 * * *'

concurrency:
group: ${{ github.workflow }}-${{ github.event.number || github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}

env:
TEST_REPO: redhat-best-practices-for-k8s/certsuite
CERTSUITE_REF: main

jobs:
# Build and store the certsuite binary
build-and-store-binary:
runs-on: ubuntu-24.04
steps:
- name: Check out code
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
with:
ref: ${{ github.sha }}

- name: Set up Go
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version-file: go.mod

- name: Clone the certsuite repository
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
with:
repository: ${{ env.TEST_REPO }}
path: certsuite
ref: ${{ env.CERTSUITE_REF }}

- name: Extract dependent Pull Requests
uses: depends-on/depends-on-action@61cb3f4a0e2c8ae4b90c9448dc57c7ba9ca24c35 # main
with:
token: ${{ secrets.GITHUB_TOKEN }}
extra-dirs: certsuite

- name: Build the certsuite binary
run: make build-certsuite-tool
working-directory: certsuite

- name: Upload certsuite binary as artifact
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
with:
name: certsuite-binary
path: certsuite/certsuite
retention-days: 1

qe-testing-minikube:
needs: [build-and-store-binary]
if: ${{ needs.build-and-store-binary.result == 'success' }}
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix:
suite: [accesscontrol, affiliatedcertification, manageability, networking, lifecycle, performance, platformalteration, observability, operator]
env:
SHELL: /bin/bash
KUBECONFIG: '/home/runner/.kube/config'
PFLT_DOCKERCONFIG: '/home/runner/.docker/config'
TEST_CERTSUITE_IMAGE_NAME: quay.io/redhat-best-practices-for-k8s/certsuite
TEST_CERTSUITE_IMAGE_TAG: localtest
DOCKER_CONFIG_DIR: '/home/runner/.docker/'
SKIP_PRELOAD_IMAGES: true # Not needed for github-hosted runs

steps:
- name: Write temporary docker file
run: |
mkdir -p /home/runner/.docker
touch ${PFLT_DOCKERCONFIG}
echo '{ "auths": {} }' >> ${PFLT_DOCKERCONFIG}

- name: Check out code
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
with:
ref: ${{ github.sha }}

- name: Set up Go
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version-file: go.mod

- name: Disable default go problem matcher
run: echo "::remove-matcher owner=go::"

- name: Check out `certsuite-sample-workload`
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
with:
repository: redhat-best-practices-for-k8s/certsuite-sample-workload
path: certsuite-sample-workload

- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y python3-pip

- name: Setup minikube k8s cluster
uses: palmsoftware/[email protected]
with:
clusterProvider: minikube
disableDefaultCni: true
numControlPlaneNodes: 1
numWorkerNodes: 2
installOLM: true
removeDefaultStorageClass: true
removeControlPlaneTaint: true

- name: Install partner resources
run: python3 -m venv .venv; source .venv/bin/activate; pip install --upgrade pip; pip install jinjanator; cp .venv/bin/jinjanate .venv/bin/j2; make install-for-qe
working-directory: certsuite-sample-workload

- name: Show pods
run: oc get pods -A

- name: Wait for all pods to be ready
run: ./scripts/wait-for-all-pods-running.sh
working-directory: certsuite-sample-workload
timeout-minutes: 10

- name: Clone the certsuite repository
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v5.0.0
with:
repository: ${{ env.TEST_REPO }}
path: certsuite
ref: ${{ env.CERTSUITE_REF }}

- name: Extract dependent Pull Requests
uses: depends-on/depends-on-action@61cb3f4a0e2c8ae4b90c9448dc57c7ba9ca24c35 # main
with:
token: ${{ secrets.GITHUB_TOKEN }}
extra-dirs: certsuite-sample-workload certsuite

- name: Download pre-built certsuite binary
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
with:
name: certsuite-binary
path: certsuite/

- name: Make binary executable
run: chmod +x certsuite/certsuite

# Only run against the binary during a scheduled run
- name: Run the tests (against binary)
uses: nick-fields/retry@ce71cc2ab81d554ebbe88c79ab5975992d79ba08 # v3.0.2
with:
timeout_minutes: 150
max_attempts: 3
command: FEATURES=${{matrix.suite}} CERTSUITE_REPO_PATH=${GITHUB_WORKSPACE}/certsuite USE_BINARY=true DISABLE_INTRUSIVE_TESTS=true ENABLE_PARALLEL=true ENABLE_FLAKY_RETRY=true JOB_ID=${{github.run_id}} make test-features

check-all-dependencies-are-merged:
runs-on: ubuntu-24.04
steps:

- name: Extract dependent PR
uses: depends-on/depends-on-action@61cb3f4a0e2c8ae4b90c9448dc57c7ba9ca24c35 # main
with:
token: ${{ secrets.GITHUB_TOKEN }}
check-unmerged-pr: true

...

Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ var _ = Describe("Access-control non-root user,", func() {

// 56427
It("one deployment, one pod, does not have securityContext RunAsUser 0", func() {
if globalhelper.IsKindCluster() {
if globalhelper.IsVanillaK8sCluster() {
// This test case deploys a pod without any securityContext fields in both pod and container level. In OCP,
// the most restrictive SecurityContextConstraint resource will be selected, making those fields to be automatically
// set with the appropriate values. In kind clusters, there's no SCC so both fields will be kept as nil, which makes
Expand Down Expand Up @@ -106,7 +106,7 @@ var _ = Describe("Access-control non-root user,", func() {

// 56429
It("two deployments, one pod each, does not have securityContext RunAsUser 0", func() {
if globalhelper.IsKindCluster() {
if globalhelper.IsVanillaK8sCluster() {
// This test case deploys a pod without any securityContext fields in both pod and container level. In OCP,
// the most restrictive SecurityContextConstraint resource will be selected, making those fields to be automatically
// set with the appropriate values. In kind clusters, there's no SCC so both fields will be kept as nil, which makes
Expand Down
2 changes: 1 addition & 1 deletion tests/accesscontrol/tests/access_control_crd_roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var _ = Describe("access-control-crd-roles", Serial, func() {
var randomCertsuiteConfigDir string

BeforeEach(func() {
if globalhelper.IsKindCluster() {
if globalhelper.IsVanillaK8sCluster() {
By("Make masters schedulable")
err := nodes.EnableMasterScheduling(globalhelper.GetAPIClient().K8sClient.CoreV1().Nodes(), true)
Expect(err).ToNot(HaveOccurred())
Expand Down
4 changes: 2 additions & 2 deletions tests/accesscontrol/tests/access_control_security_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ var _ = Describe("Access-control security-context,", func() {

// 63736
It("one deployment, one pod, one container, has allowed security context", func() {
if globalhelper.IsKindCluster() {
if globalhelper.IsVanillaK8sCluster() {
Skip("Skip on kind cluster")
}

Expand Down Expand Up @@ -102,7 +102,7 @@ var _ = Describe("Access-control security-context,", func() {

// 63738
It("two deployments, one pod each, one container each, both have allowed security context", func() {
if globalhelper.IsKindCluster() {
if globalhelper.IsVanillaK8sCluster() {
Skip("Skip on kind cluster")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ var _ = Describe("Access-control sys-nice_capability", Ordered, Serial, Label("r
}

// Skip all if running in a kind cluster
if globalhelper.IsKindCluster() {
if globalhelper.IsVanillaK8sCluster() {
skipTestSuite = true
Skip("Kind cluster detected")
}
Expand Down Expand Up @@ -449,7 +449,7 @@ var _ = Describe("Access-control sys-nice_capability check, non-realtime kernel"

pod := &podList.Items[0]
By("Ensure pod " + pod.Name + " has not added SYS_NICE cap")
if globalhelper.IsKindCluster() {
if globalhelper.IsVanillaK8sCluster() {
Expect(pod.Spec.Containers[0].SecurityContext).To(BeNil())
Expect(pod.Spec.Containers[1].SecurityContext).To(BeNil())
} else {
Expand All @@ -459,7 +459,7 @@ var _ = Describe("Access-control sys-nice_capability check, non-realtime kernel"

pod = &podList.Items[1]
By("Ensure pod " + pod.Name + " has not added SYS_NICE cap")
if globalhelper.IsKindCluster() {
if globalhelper.IsVanillaK8sCluster() {
Expect(pod.Spec.Containers[0].SecurityContext).To(BeNil())
Expect(pod.Spec.Containers[1].SecurityContext).To(BeNil())
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ var isCloudCasaAlreadyLabeled bool

var _ = SynchronizedBeforeSuite(func() {

if !globalhelper.IsKindCluster() {
if !globalhelper.IsVanillaK8sCluster() {
// Always install Helm v3 right before running the suite
By("Install helm v3")
cmd := exec.Command("/bin/bash", "-c",
Expand Down Expand Up @@ -88,7 +88,7 @@ var _ = SynchronizedBeforeSuite(func() {
Expect(err).ToNot(HaveOccurred())
}

if !globalhelper.IsKindCluster() {
if !globalhelper.IsVanillaK8sCluster() {
By("Ensure openshift-marketplace namespace exists")
err = globalhelper.CreateNamespace("openshift-marketplace")
Expect(err).ToNot(HaveOccurred())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var _ = Describe("Affiliated-certification container-is-certified-digest,", Seri
var randomCertsuiteConfigDir string

BeforeEach(func() {
if globalhelper.IsKindCluster() {
if globalhelper.IsVanillaK8sCluster() {
Skip("Skip test due to image pull missing credentials in Kind")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ var _ = Describe("Affiliated-certification helm-version,", Serial, func() {
var randomCertsuiteConfigDir string

BeforeEach(func() {
if globalhelper.IsKindCluster() {
if globalhelper.IsVanillaK8sCluster() {
Skip("Skipping helm version test on Kind cluster")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ var _ = Describe("Affiliated-certification operator certification,", Serial, fun
tsparams.TestCertificationNameSpace)

// If Kind cluster, skip.
if globalhelper.IsKindCluster() {
if globalhelper.IsVanillaK8sCluster() {
Skip("This test is not supported on Kind cluster")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ var _ = Describe("Affiliated-certification helm chart certification,", Serial, f
var randomCertsuiteConfigDir string

BeforeEach(func() {
if globalhelper.IsKindCluster() {
if globalhelper.IsVanillaK8sCluster() {
Skip("Skipping helm chart test on Kind cluster")
}

Expand Down
17 changes: 17 additions & 0 deletions tests/globalhelper/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,23 @@ func IsKindCluster() bool {
return cmd.Run() == nil
}

// Returns true if the cluster is a minikube cluster, otherwise false.
func IsMinikubeCluster() bool {
cmd := exec.CommandContext(context.TODO(),
"oc",
"cluster-info", "--context", "minikube",
">/dev/null", "2>&1")

return cmd.Run() == nil
}

// Returns true if the cluster is a vanilla Kubernetes cluster (Kind or Minikube),
// otherwise false. This is useful for skipping OpenShift-specific tests that
// require features like SecurityContextConstraints, OCP lifecycle, etc.
func IsVanillaK8sCluster() bool {
return IsKindCluster() || IsMinikubeCluster()
}

// Returns true if the cluster is a CRC (Code Ready Containers) cluster, otherwise false.
// CRC clusters are typically single-node OpenShift clusters used for development.
func IsCRCCluster() bool {
Expand Down
2 changes: 1 addition & 1 deletion tests/lifecycle/tests/lifecycle_cpu_isolation.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ var _ = Describe("lifecycle-cpu-isolation", Serial, func() {
[]string{}, randomCertsuiteConfigDir)
Expect(err).ToNot(HaveOccurred())

if globalhelper.IsKindCluster() && runtime.NumCPU() <= 2 {
if globalhelper.IsVanillaK8sCluster() && runtime.NumCPU() <= 2 {
Skip("This test requires more than 2 CPU cores")
}
})
Expand Down
2 changes: 1 addition & 1 deletion tests/lifecycle/tests/lifecycle_crd_scaling.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ var _ = Describe("lifecycle-crd-scaling", Serial, func() {
var randomCertsuiteConfigDir string

BeforeEach(func() {
if globalhelper.IsKindCluster() {
if globalhelper.IsVanillaK8sCluster() {
By("Make masters schedulable")
err := nodes.EnableMasterScheduling(globalhelper.GetAPIClient().Nodes(), true)
Expect(err).ToNot(HaveOccurred())
Expand Down
2 changes: 1 addition & 1 deletion tests/lifecycle/tests/lifecycle_pod_high_availability.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ var _ = Describe("lifecycle-pod-high-availability", Serial, func() {
var randomCertsuiteConfigDir string

BeforeEach(func() {
if globalhelper.IsKindCluster() {
if globalhelper.IsVanillaK8sCluster() {
By("Make masters schedulable")
err := nodes.EnableMasterScheduling(globalhelper.GetAPIClient().Nodes(), true)
Expect(err).ToNot(HaveOccurred())
Expand Down
2 changes: 1 addition & 1 deletion tests/lifecycle/tests/lifecycle_pod_recreation.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ var _ = Describe("lifecycle-pod-recreation", Serial, func() {
err := os.Setenv("CERTSUITE_NON_INTRUSIVE_ONLY", "false")
Expect(err).ToNot(HaveOccurred())

if globalhelper.IsKindCluster() {
if globalhelper.IsVanillaK8sCluster() {
By("Make masters schedulable")
err := nodes.EnableMasterScheduling(globalhelper.GetAPIClient().Nodes(), true)
Expect(err).ToNot(HaveOccurred())
Expand Down
2 changes: 1 addition & 1 deletion tests/lifecycle/tests/lifecycle_statefulset_scaling.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ var _ = Describe("lifecycle-statefulset-scaling", Serial, func() {
err := os.Setenv("CERTSUITE_NON_INTRUSIVE_ONLY", "false")
Expect(err).ToNot(HaveOccurred())

if globalhelper.IsKindCluster() {
if globalhelper.IsVanillaK8sCluster() {
By("Make masters schedulable")
err := nodes.EnableMasterScheduling(globalhelper.GetAPIClient().Nodes(), true)
Expect(err).ToNot(HaveOccurred())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ var _ = Describe("Networking dpdk-cpu-pinning-exec-probe,", func() {
[]string{}, randomCertsuiteConfigDir)
Expect(err).ToNot(HaveOccurred())

if globalhelper.IsKindCluster() {
if globalhelper.IsVanillaK8sCluster() {
Skip("DPDK is not supported on Kind cluster. Skipping.")
}

Expand Down
Loading
Loading