diff --git a/.github/workflows/e2e-nightly.yml b/.github/workflows/e2e-nightly.yml new file mode 100644 index 0000000..d2876e6 --- /dev/null +++ b/.github/workflows/e2e-nightly.yml @@ -0,0 +1,58 @@ +name: e2e (nightly) + +# test/e2e 스위트는 작성돼 있는데 **어떤 워크플로도 호출하지 않아** 한 번도 +# 게이트 역할을 하지 못했다 (`make test-e2e` 수동 실행 전용). 가장 비싼 테스트가 +# 죽어 있던 셈이라 여기서 되살린다. +# +# PR 이 아니라 nightly 인 이유: kind 클러스터 생성 + 이미지 빌드 + cert-manager +# 설치까지 도는 스위트라 PR 지연이 크다. 회귀는 하루 안에 잡히면 충분하고, +# 급할 땐 workflow_dispatch 로 즉시 돌린다. + +on: + schedule: + - cron: "37 18 * * *" # 매일 03:37 KST + workflow_dispatch: + # 이 워크플로 자신을 고칠 때는 PR 에서 실제로 돌려본다 — e2e 배선 변경을 + # 검증 없이 머지하면 nightly 가 조용히 죽는다 (게이트의 자기 감시). + pull_request: + paths: + - ".github/workflows/e2e-nightly.yml" + - "Makefile" # test-e2e 레시피(타임아웃·kind 변수)가 여기 산다 + +permissions: + contents: read + +concurrency: + group: e2e-${{ github.repository }} + cancel-in-progress: false + +jobs: + e2e: + name: kind e2e + runs-on: ubuntu-latest + timeout-minutes: 60 + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-go@v6 + with: + go-version-file: go.mod + cache: true + - name: Install kind + run: | + set -euo pipefail + curl -fsSLo /tmp/kind https://kind.sigs.k8s.io/dl/v0.30.0/kind-linux-amd64 + chmod +x /tmp/kind + sudo install /tmp/kind /usr/local/bin/kind + kind version + # 스위트가 BeforeSuite 에서 make docker-build + kind load 를 직접 수행하므로 + # 여기서는 kind 바이너리만 깔면 된다. IMG 는 로컬 빌드·로드 전용이라 + # 레지스트리에 도달할 필요가 없다 — 사설 호스트명 기본값을 피해 중립 태그를 준다. + - name: make test-e2e + env: + IMG: localhost/keiailab/mongodb-operator:e2e-ci + run: make test-e2e + - name: Dump cluster state on failure + if: failure() + run: | + kubectl get pods -A -o wide || true + kubectl describe pods -A | tail -200 || true diff --git a/Makefile b/Makefile index 28c4279..149390f 100644 --- a/Makefile +++ b/Makefile @@ -412,9 +412,14 @@ setup-test-e2e: ## Set up a Kind cluster for e2e tests if it does not exist. $(KIND) create cluster --name $(KIND_CLUSTER) --config test/e2e/kind-config.yaml ;; \ esac +# e2e 스위트 타임아웃. go test 기본값은 10m 인데 이 스위트는 kind 생성 + 이미지 빌드 + +# cert-manager 설치 + StatefulSet 롤아웃까지 도느라 항상 그 벽에 걸렸다 — 스위트가 작성돼 +# 있으면서도 CI 에 한 번도 붙지 못한 실제 이유다. +E2E_TIMEOUT ?= 45m + .PHONY: test-e2e test-e2e: setup-test-e2e manifests generate fmt vet ## Run e2e tests against the Kind cluster. - KIND=$(KIND) KIND_CLUSTER=$(KIND_CLUSTER) go test -tags=e2e ./test/e2e/ -v -ginkgo.v + KIND=$(KIND) KIND_CLUSTER=$(KIND_CLUSTER) go test -tags=e2e ./test/e2e/ -v -ginkgo.v -timeout $(E2E_TIMEOUT) $(MAKE) cleanup-test-e2e .PHONY: cleanup-test-e2e diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go index 7289967..1f331e1 100644 --- a/test/e2e/e2e_suite_test.go +++ b/test/e2e/e2e_suite_test.go @@ -65,6 +65,19 @@ var _ = BeforeSuite(func() { configureKubectlKubeRC() setupCertManager() + + // CRD + operator 설치는 **모든 spec 보다 먼저** 일어나야 한다. + // 구 구조는 search_test.go 의 BeforeAll 에서만 `make deploy` 를 했는데, + // Ginkgo 는 최상위 컨테이너 순서를 무작위화하므로 그보다 먼저 뽑힌 컨테이너는 + // CRD 가 없는 클러스터에 CR 을 apply 하다 `no matches for kind "MongoDB"` 로 + // 죽었다 (첫 CI 실행: 19 Passed / 10 Failed — 전부 이 클래스). + By("deploying CRDs + operator (make deploy)") + _, err = utils.Run(exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", managerImage))) + ExpectWithOffset(1, err).NotTo(HaveOccurred(), "Failed to deploy CRDs + operator") + + By("waiting for controller-manager rollout (best-effort)") + _, _ = utils.Run(exec.Command("kubectl", "-n", "mongodb-operator-system", "rollout", "status", + "deploy/mongodb-operator-controller-manager", "--timeout=150s")) }) var _ = AfterSuite(func() { diff --git a/test/e2e/search_test.go b/test/e2e/search_test.go index c29ef61..552b1f5 100644 --- a/test/e2e/search_test.go +++ b/test/e2e/search_test.go @@ -53,12 +53,8 @@ const ( var _ = Describe("MongoDBSearch $vectorSearch Round-Trip (PR5)", Ordered, func() { BeforeAll(func() { - By("deploying operator (make deploy — self-contained)") - _, err := utils.Run(exec.Command("make", "deploy", fmt.Sprintf("IMG=%s", managerImage))) - Expect(err).NotTo(HaveOccurred(), "make deploy") - By("waiting for operator controller-manager rollout (best-effort)") - _, _ = utils.Run(exec.Command("kubectl", "-n", "mongodb-operator-system", "rollout", "status", - "deploy/mongodb-operator-controller-manager", "--timeout=150s")) + // operator/CRD 설치는 BeforeSuite 로 이동했다 — 여기서만 하면 Ginkgo 의 + // 컨테이너 순서 무작위화 때문에 다른 spec 이 CRD 없이 돌 수 있다. By("pre-caching mongot image on the kind node (avoid slow Docker Hub pull inside the timed spec)") // mongot 이미지(~1.3GB)를 노드 containerd 에 미리 적재한다. 핀된 :0.69.1(IfNotPresent)가 이 @@ -109,7 +105,7 @@ spec: `, searchMongoName, searchNS, searchCRName, searchNS, searchMongoName) cmd := exec.Command("kubectl", "apply", "-f", "-") cmd.Stdin = strings.NewReader(manifest) - _, err = utils.Run(cmd) + _, err := utils.Run(cmd) Expect(err).NotTo(HaveOccurred(), "MongoDB + MongoDBSearch apply") })