ci(test): run Go tests with race detector (#7311)

ci(test): run Go tests with race detector (#7299)

* ci: run Go tests with race detector

* ci: use standard race test targets

* ci: avoid coverage during controller race tests

* test: document trusted external request targets

* ci: fold account runtime tests into unit tests

* test: always run account testcontainers tests

Co-authored-by: zijiren <84728412+zijiren233@users.noreply.github.com>
This commit is contained in:
github-actions[bot]
2026-09-07 13:52:16 +08:00
committed by GitHub
co-authored by zijiren
parent f1c9358f99
commit 058fe3f41c
44 changed files with 485 additions and 621 deletions
+21
View File
@@ -81,6 +81,27 @@ jobs:
working-directory: controllers/${{ inputs.module_path }}
args: --color=always --config=${{ github.workspace }}/.golangci.yml
unit-test:
name: Test ${{ inputs.module_name }} with race detector
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Golang with cache
uses: magnetikonline/action-golang-cache@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Install Dependencies
run: sudo apt update && sudo apt install -y libgpgme-dev libbtrfs-dev libdevmapper-dev
- name: Run Tests with race detector
working-directory: controllers/${{ inputs.module_path }}
env:
USE_EXISTING_CLUSTER: "false"
run: make test
image-build:
runs-on: ubuntu-24.04
permissions:
+19
View File
@@ -74,6 +74,25 @@ concurrency:
cancel-in-progress: true
jobs:
shared-unit-test:
name: Test shared controller packages with race detector
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Golang with cache
uses: magnetikonline/action-golang-cache@v5
with:
go-version-file: controllers/pkg/go.mod
- name: Install Dependencies
run: sudo apt update && sudo apt install -y libgpgme-dev libbtrfs-dev libdevmapper-dev
- name: Run Tests with race detector
working-directory: controllers/pkg
run: go test -race ./... -count=1 -v
detect-changes:
uses: ./.github/workflows/detect-changes.yml
with:
+5 -9
View File
@@ -69,11 +69,9 @@ jobs:
working-directory: service/${{ inputs.module }}
args: --color=always --config=${{ github.workspace }}/.golangci.yml
account-dao-runtime:
name: Account DAO MongoDB runtime test
if: ${{ inputs.module == 'account' }}
unit-test:
name: Test ${{ inputs.module }} with race detector
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -83,11 +81,9 @@ jobs:
with:
go-version: ${{ env.GO_VERSION }}
- name: Run MongoDB runtime test
working-directory: service/account
env:
TESTCONTAINERS_REQUIRED: "true"
run: go test ./dao -run '^TestGet(Workspace)?ConsumptionAmountWithMongoRuntime$' -count=1 -v
- name: Run Tests with race detector
working-directory: service/${{ inputs.module }}
run: go test -race ./... -count=1 -v
image-build:
strategy:
+16
View File
@@ -75,6 +75,22 @@ concurrency:
cancel-in-progress: true
jobs:
shared-unit-test:
name: Test shared service packages with race detector
runs-on: ubuntu-24.04
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Golang with cache
uses: magnetikonline/action-golang-cache@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Run Tests with race detector
working-directory: service
run: go test -race ./... -count=1 -v
detect-changes:
uses: ./.github/workflows/detect-changes.yml
with:
+23
View File
@@ -104,6 +104,29 @@ jobs:
# args between =, not space
args: --color=always --config=${{ github.workspace }}/.golangci.yml
unit-test:
name: Test ${{ matrix.workdir }} with race detector
needs: [resolve-modules]
runs-on: ubuntu-24.04
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.resolve-modules.outputs.matrix) }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Golang with cache
uses: magnetikonline/action-golang-cache@v5
with:
go-version: ${{ env.GO_VERSION }}
- name: Install Dependencies
run: sudo apt update && sudo apt install -y libgpgme-dev libbtrfs-dev libdevmapper-dev
- name: Run Tests with race detector
working-directory: ${{ matrix.workdir }}
run: make test
image-build:
runs-on: ubuntu-24.04
permissions:
+2 -2
View File
@@ -56,8 +56,8 @@ vet: ## Run go vet against code.
go vet ./...
.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) --arch=amd64 use $(ENVTEST_K8S_VERSION) -p path)" go test ./... -coverprofile cover.out
test: ## Run tests.
go test -race ./... -count=1
##@ Build
@@ -29,6 +29,13 @@ import (
)
func TestAccountReconciler_BillingCVM(t *testing.T) {
requireAccountExternalTest(t,
database.CVMMongoURI,
database.MongoURI,
database.GlobalCockroachURI,
database.LocalCockroachURI,
"LOCAL_REGION",
)
dbCtx := context.Background()
cvmDBClient, err := mongo.NewMongoInterface(dbCtx, os.Getenv(database.CVMMongoURI))
if err != nil {
@@ -78,8 +85,15 @@ func TestAccountReconciler_BillingCVM(t *testing.T) {
}
func TestAccountV2_GetAccountConfig(t *testing.T) {
t.Setenv("LOCAL_REGION", "")
v2Account, err := cockroach.NewCockRoach("", "")
requireAccountExternalTest(t,
database.GlobalCockroachURI,
database.LocalCockroachURI,
"LOCAL_REGION",
)
v2Account, err := cockroach.NewCockRoach(
os.Getenv(database.GlobalCockroachURI),
os.Getenv(database.LocalCockroachURI),
)
if err != nil {
t.Fatalf("unable to connect to cockroach: %v", err)
}
@@ -118,3 +132,15 @@ func TestAccountV2_GetAccountConfig(t *testing.T) {
}
t.Logf("success get account config:\n%s", string(data))
}
func requireAccountExternalTest(t *testing.T, envNames ...string) {
t.Helper()
if os.Getenv("RUN_ACCOUNT_EXTERNAL_TESTS") != "true" {
t.Skip("set RUN_ACCOUNT_EXTERNAL_TESTS=true to run account external tests")
}
for _, name := range envNames {
if os.Getenv(name) == "" {
t.Skipf("requires %s", name)
}
}
}
@@ -15,6 +15,7 @@
package controllers
import (
"os"
"testing"
"github.com/labring/sealos/controllers/pkg/database"
@@ -22,16 +23,8 @@ import (
"github.com/labring/sealos/controllers/pkg/types"
)
var (
testV2GlobalDBURI = ""
testV2LocalDBURI = ""
)
func TestAccountV2_CreateAccount(t *testing.T) {
account, err := database.NewAccountV2(testV2GlobalDBURI, testV2LocalDBURI)
if err != nil {
t.Errorf("failed to new account : %v", err)
}
account := newExternalAccountV2(t)
defer func() {
if err := account.Close(); err != nil {
t.Errorf("failed close connection: %v", err)
@@ -51,10 +44,7 @@ func TestAccountV2_CreateAccount(t *testing.T) {
}
func TestAccountV2_GetAccount(t *testing.T) {
account, err := database.NewAccountV2(testV2GlobalDBURI, testV2LocalDBURI)
if err != nil {
t.Errorf("failed to new account : %v", err)
}
account := newExternalAccountV2(t)
defer func() {
if err := account.Close(); err != nil {
t.Errorf("failed close connection: %v", err)
@@ -74,10 +64,7 @@ func TestAccountV2_GetAccount(t *testing.T) {
}
func TestAccountV2_GetUser(t *testing.T) {
account, err := database.NewAccountV2(testV2GlobalDBURI, testV2LocalDBURI)
if err != nil {
t.Errorf("failed to new account : %v", err)
}
account := newExternalAccountV2(t)
defer func() {
if err := account.Close(); err != nil {
t.Errorf("failed close connection: %v", err)
@@ -91,16 +78,13 @@ func TestAccountV2_GetUser(t *testing.T) {
}
func TestAccountV2_TransferAccount(t *testing.T) {
account, err := database.NewAccountV2(testV2GlobalDBURI, testV2LocalDBURI)
if err != nil {
t.Errorf("failed to new account : %v", err)
}
account := newExternalAccountV2(t)
defer func() {
if err := account.Close(); err != nil {
t.Errorf("failed close connection: %v", err)
}
}()
err = account.TransferAccount(
err := account.TransferAccount(
&types.UserQueryOpts{Owner: "eoxwhh80"},
&types.UserQueryOpts{Owner: "1ycieb5b"},
85*cockroach.BaseUnit,
@@ -122,10 +106,7 @@ func TestAccountV2_TransferAccount(t *testing.T) {
}
func TestAccountV2_AddBalance(t *testing.T) {
account, err := database.NewAccountV2(testV2GlobalDBURI, testV2LocalDBURI)
if err != nil {
t.Fatalf("failed to new account : %v", err)
}
account := newExternalAccountV2(t)
defer func() {
if err := account.Close(); err != nil {
t.Errorf("failed close connection: %v", err)
@@ -151,3 +132,20 @@ func TestAccountV2_AddBalance(t *testing.T) {
(aa.Balance-aa.DeductionBalance)/cockroach.BaseUnit,
)
}
func newExternalAccountV2(t *testing.T) database.AccountV2 {
t.Helper()
requireAccountExternalTest(t,
database.GlobalCockroachURI,
database.LocalCockroachURI,
"LOCAL_REGION",
)
account, err := database.NewAccountV2(
os.Getenv(database.GlobalCockroachURI),
os.Getenv(database.LocalCockroachURI),
)
if err != nil {
t.Fatalf("failed to create account client: %v", err)
}
return account
}
@@ -79,10 +79,16 @@ const (
// TestReconcileAllFinalUser 测试方法
func TestReconcileAllFinalUser(t *testing.T) {
t.Setenv("LOCAL_REGION", "4b55d7c5-ff65-4eb7-9bcf-726c730a0fad")
requireAccountMaintenanceTest(
t,
database.GlobalCockroachURI,
database.LocalCockroachURI,
"LOCAL_REGION",
EnvJwtSecret,
)
account, err := database.NewAccountV2(
"postgresql://sealos:fb9jg8te4x78ocqrr2vgbs99qauh9flfd1u6g300kq7ywjay3ah7cndr60udd6wg@192.168.10.35:32749/global",
"postgresql://sealos:vtzfqp8hbkn7jdstzkbac6cd4u84n6w3s28f8wnqzrts2b96xcs7v58r1a18ihds@192.168.10.35:32749/local",
os.Getenv(database.GlobalCockroachURI),
os.Getenv(database.LocalCockroachURI),
)
if err != nil {
t.Fatalf("failed to new account: %v", err)
@@ -104,10 +110,7 @@ func TestReconcileAllFinalUser(t *testing.T) {
}
}
jwtManager := utils.NewJWTManager(
"98r7c1zjllv4kgn67trj1cknprnpcwup3hh38b44puhfrbkmzy9bjipbw4tclr3f",
time.Hour*24,
)
jwtManager := utils.NewJWTManager(os.Getenv(EnvJwtSecret), time.Hour*24)
// 获取全部 Debt 状态为 FinalDeletionPeriod 的用户
allUserUID := make([]uuid.UUID, 0)
@@ -247,19 +250,19 @@ func sendFlushDebtResourceStatusRequest(
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Content-Type", "application/json")
client := http.Client{}
client := http.Client{Timeout: 30 * time.Second}
resp, err := client.Do(req)
if err != nil {
lastErr = fmt.Errorf("failed to send request: %w", err)
} else {
defer resp.Body.Close()
if resp.StatusCode == http.StatusOK {
lastErr = nil
_ = resp.Body.Close()
break
}
lastErr = fmt.Errorf("unexpected status code: %d", resp.StatusCode)
_ = resp.Body.Close()
}
if attempt < maxRetries {
@@ -288,12 +291,19 @@ type regionConfig struct {
RegionUID string `json:"region_uid"`
}
var regions = []regionConfig{}
// 1. pause account controller
// 2. convert all region debt
// 3. upgrade and restore the account controller
func TestConvertDebt(t *testing.T) {
requireAccountMaintenanceTest(t, "ACCOUNT_DEBT_MIGRATION_REGIONS")
var regions []regionConfig
regionsJSON := os.Getenv("ACCOUNT_DEBT_MIGRATION_REGIONS")
if err := json.Unmarshal([]byte(regionsJSON), &regions); err != nil {
t.Fatalf("failed to parse ACCOUNT_DEBT_MIGRATION_REGIONS: %v", err)
}
if len(regions) == 0 {
t.Fatal("ACCOUNT_DEBT_MIGRATION_REGIONS must contain at least one region")
}
for i := range regions {
// 先获取全部的debt crd
fmt.Printf(
@@ -347,6 +357,18 @@ func TestConvertDebt(t *testing.T) {
}
}
func requireAccountMaintenanceTest(t *testing.T, envNames ...string) {
t.Helper()
if os.Getenv("RUN_ACCOUNT_MAINTENANCE_TESTS") != "true" {
t.Skip("set RUN_ACCOUNT_MAINTENANCE_TESTS=true to run account maintenance tests")
}
for _, name := range envNames {
if os.Getenv(name) == "" {
t.Skipf("requires %s", name)
}
}
}
func convertAllDebtCr(account database.AccountV2, clt client.Client) error {
// 1. 获取已存在的 user_uid
// 2. 预加载所有 userID -> userUID
@@ -261,6 +261,7 @@ func sendFlushQuotaRequest(
maxRetries := 3
for attempt := 1; attempt <= maxRetries; attempt++ {
// #nosec G704 -- domains come from operator-managed region records.
req, err := http.NewRequestWithContext(
context.Background(),
http.MethodPost,
@@ -275,6 +276,7 @@ func sendFlushQuotaRequest(
req.Header.Set("Content-Type", "application/json")
client := http.Client{}
// #nosec G704 -- domains come from operator-managed region records.
resp, err := client.Do(req)
if err != nil {
lastErr = fmt.Errorf("failed to send request: %w", err)
@@ -2,6 +2,8 @@ package controllers
import (
"fmt"
"os"
"strings"
"testing"
"time"
@@ -12,10 +14,19 @@ import (
)
func Test_sendFlushQuotaRequest(t *testing.T) {
regions := []string{""}
jwtManager := utils.NewJWTManager("", time.Hour)
t.Setenv("LOCAL_REGION", "")
account, err := database.NewAccountV2("", "")
requireAccountExternalTest(t,
database.GlobalCockroachURI,
database.LocalCockroachURI,
"LOCAL_REGION",
"ACCOUNT_API_JWT_SECRET",
"ACCOUNT_TEST_REGION_DOMAINS",
)
regions := strings.Split(os.Getenv("ACCOUNT_TEST_REGION_DOMAINS"), ",")
jwtManager := utils.NewJWTManager(os.Getenv("ACCOUNT_API_JWT_SECRET"), time.Hour)
account, err := database.NewAccountV2(
os.Getenv(database.GlobalCockroachURI),
os.Getenv(database.LocalCockroachURI),
)
if err != nil {
t.Fatalf("failed to new account: %v", err)
}
@@ -1,120 +0,0 @@
/*
Copyright 2023.
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 controllers
import (
"path/filepath"
"testing"
"time"
accountv1 "github.com/labring/sealos/controllers/account/api/v1"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
corev1 "k8s.io/api/core/v1"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
)
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
var (
cfg *rest.Config
k8sClient client.Client
testEnv *envtest.Environment
)
func TestAPIs(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecsWithDefaultAndCustomReporters(t, "Controller Suite", []Reporter{})
}
var _ = BeforeSuite(func() {
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
ErrorIfCRDPathMissing: true,
}
var err error
// cfg is defined in this file globally.
cfg, err = testEnv.Start()
Expect(err).NotTo(HaveOccurred())
Expect(cfg).NotTo(BeNil())
err = accountv1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
err = corev1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
//+kubebuilder:scaffold:scheme
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
Expect(err).NotTo(HaveOccurred())
Expect(k8sClient).NotTo(BeNil())
}, 60)
var _ = AfterSuite(func() {
By("tearing down the test environment")
err := testEnv.Stop()
Expect(err).NotTo(HaveOccurred())
})
func TestCalculateBillingHours(t *testing.T) {
// lastUpdateTime := time.Date(2021, 11, 1, 10, 35, 20, 0, time.UTC)
// currentHourTime := time.Date(2021, 11, 1, 14, 0, 0, 0, time.UTC)
lastUpdateTime := time.Date(2021, time.November, 1, 10, 0, 0, 0, time.UTC)
currentHourTime := time.Date(2021, time.November, 1, 14, 0, 0, 0, time.UTC)
// lastUpdateTime := time.Date(2021, 11, 1, 14, 0, 0, 0, time.UTC)
// currentHourTime := time.Date(2021, 11, 1, 14, 0, 0, 0, time.UTC)
expected := []time.Time{
time.Date(2021, time.November, 1, 11, 0, 0, 0, time.UTC),
time.Date(2021, time.November, 1, 12, 0, 0, 0, time.UTC),
time.Date(2021, time.November, 1, 13, 0, 0, 0, time.UTC),
time.Date(2021, time.November, 1, 14, 0, 0, 0, time.UTC),
}
result := CalculateBillingHours(lastUpdateTime, currentHourTime)
if len(result) != len(expected) {
t.Fatalf("expected %d billing hours, but got %d", len(expected), len(result))
}
for i := range result {
if !result[i].Equal(expected[i]) {
t.Errorf("expected billing hour %v, but got %v", expected[i], result[i])
}
}
}
func CalculateBillingHours(lastUpdateTime, currentHourTime time.Time) []time.Time {
needBillingHours := make([]time.Time, 0)
for t := lastUpdateTime.Truncate(time.Hour).Add(time.Hour); t.Before(currentHourTime) || t.Equal(currentHourTime); t = t.Add(time.Hour) {
needBillingHours = append(needBillingHours, t)
}
return needBillingHours
}
@@ -24,6 +24,7 @@ import (
)
func TestSendSms(t *testing.T) {
requireMessagingTest(t, "ak", "sk", "phone", "sign_name", "template_code")
clt, err := CreateSMSClient(os.Getenv("ak"), os.Getenv("sk"), "dysmsapi.aliyuncs.com")
if err != nil {
t.Fatal(err)
@@ -42,3 +43,15 @@ func TestSendSms(t *testing.T) {
t.Fatal(fmt.Errorf("send sms failed: %w", err))
}
}
func requireMessagingTest(t *testing.T, envNames ...string) {
t.Helper()
if os.Getenv("RUN_MESSAGING_TESTS") != "true" {
t.Skip("set RUN_MESSAGING_TESTS=true to run messaging provider tests")
}
for _, name := range envNames {
if os.Getenv(name) == "" {
t.Skipf("requires %s", name)
}
}
}
@@ -23,6 +23,13 @@ import (
)
func TestSendVms(t *testing.T) {
requireMessagingTest(t,
"VMS_AK",
"VMS_SK",
"VMS_TEST_PHONE",
"VMS_TEST_TEMPLATE",
"VMS_TEST_NUMBER_POOL_NO",
)
vms.DefaultInstance.SetAccessKey(os.Getenv("VMS_AK"))
vms.DefaultInstance.SetSecretKey(os.Getenv("VMS_SK"))
testData := struct {
@@ -31,9 +38,9 @@ func TestSendVms(t *testing.T) {
numberPollNo string
sendTime time.Time
}{
phone: "",
template: "",
numberPollNo: "",
phone: os.Getenv("VMS_TEST_PHONE"),
template: os.Getenv("VMS_TEST_TEMPLATE"),
numberPollNo: os.Getenv("VMS_TEST_NUMBER_POOL_NO"),
sendTime: time.Now(),
}
err := SendVms(
+2 -2
View File
@@ -63,8 +63,8 @@ vet: ## Run go vet against code.
go vet ./...
.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) --arch=amd64 use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out
test: ## Run tests.
go test -race ./... -count=1
##@ Build
+5 -1
View File
@@ -44,6 +44,10 @@ fmt: ## Run go fmt against code.
vet: ## Run go vet against code.
go vet ./...
.PHONY: test
test: ## Run tests.
go test -race ./... -count=1
##@ Build
.PHONY: build
@@ -83,4 +87,4 @@ docker-buildx: test ## Build and push docker image for the manager for cross-pla
docker buildx use project-v3-builder
- docker buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross .
- docker buildx rm project-v3-builder
rm Dockerfile.cross
rm Dockerfile.cross
+5 -1
View File
@@ -44,6 +44,10 @@ fmt: ## Run go fmt against code.
vet: ## Run go vet against code.
go vet ./...
.PHONY: test
test: ## Run tests.
go test -race ./... -count=1
##@ Build
.PHONY: build
@@ -86,4 +90,4 @@ docker-buildx: test ## Build and push docker image for the manager for cross-pla
docker buildx use project-v3-builder
- docker buildx build --push --platform=$(PLATFORMS) --tag ${IMG} -f Dockerfile.cross .
- docker buildx rm project-v3-builder
rm Dockerfile.cross
rm Dockerfile.cross
+4 -2
View File
@@ -59,8 +59,10 @@ vet: ## Run go vet against code.
go vet ./...
.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out
test: ## Run tests.
@LD_FLAGS=""; \
[ -n "$(LICENSE_KEY)" ] && LD_FLAGS="-X ${CONTROLLER_PKG}.encryptionKey=${LICENSE_KEY}"; \
go test -race -ldflags "$${LD_FLAGS}" ./... -count=1
##@ Build
@@ -1,81 +0,0 @@
/*
Copyright 2023.
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 controller
import (
"path/filepath"
"testing"
licensev1 "github.com/labring/sealos/controllers/license/api/v1"
notificationv1 "github.com/labring/sealos/controllers/pkg/notification/api/v1"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
)
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
var (
cfg *rest.Config
k8sClient client.Client
testEnv *envtest.Environment
)
func TestControllers(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Controller Suite")
}
var _ = BeforeSuite(func() {
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "..", "config", "crd", "bases")},
ErrorIfCRDPathMissing: true,
}
var err error
// cfg is defined in this file globally.
cfg, err = testEnv.Start()
Expect(err).NotTo(HaveOccurred())
Expect(cfg).NotTo(BeNil())
err = licensev1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
err = notificationv1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
//+kubebuilder:scaffold:scheme
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
Expect(err).NotTo(HaveOccurred())
Expect(k8sClient).NotTo(BeNil())
})
var _ = AfterSuite(func() {
By("tearing down the test environment")
err := testEnv.Stop()
Expect(err).NotTo(HaveOccurred())
})
@@ -16,6 +16,7 @@ package license
import (
"encoding/base64"
"os"
"testing"
"time"
@@ -28,6 +29,9 @@ import (
func newTestLicense(t *testing.T) (*licensev1.License, *utilclaims.Claims) {
t.Helper()
if os.Getenv("LICENSE_KEY") == "" {
t.Skip("requires LICENSE_KEY to sign test licenses")
}
decodeKey, err := base64.StdEncoding.DecodeString(key.GetEncryptionKey())
if err != nil {
t.Fatalf("failed to decode encryption key: %v", err)
+2 -2
View File
@@ -56,8 +56,8 @@ vet: ## Run go vet against code.
go vet ./...
.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) --arch=amd64 use $(ENVTEST_K8S_VERSION) -p path)" go test ./... -coverprofile cover.out
test: ## Run tests.
go test -race ./... -count=1
##@ Build
@@ -1,78 +0,0 @@
/*
Copyright 2023.
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 controllers
import (
"path/filepath"
"testing"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
nodev1 "k8s.io/api/node/v1"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
)
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
var (
cfg *rest.Config
k8sClient client.Client
testEnv *envtest.Environment
)
func TestAPIs(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Controller Suite")
}
var _ = BeforeSuite(func() {
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
ErrorIfCRDPathMissing: false,
}
var err error
// cfg is defined in this file globally.
cfg, err = testEnv.Start()
Expect(err).NotTo(HaveOccurred())
Expect(cfg).NotTo(BeNil())
err = nodev1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
//+kubebuilder:scaffold:scheme
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
Expect(err).NotTo(HaveOccurred())
Expect(k8sClient).NotTo(BeNil())
})
var _ = AfterSuite(func() {
By("tearing down the test environment")
err := testEnv.Stop()
Expect(err).NotTo(HaveOccurred())
})
@@ -22,17 +22,9 @@ import (
"github.com/labring/sealos/controllers/pkg/types"
)
type TestConfig struct {
RegionID string
V2GlobalDBURI string
V2LocalDBURI string
}
var testConfig = TestConfig{}
func TestCockroach_GetUserOauthProvider(t *testing.T) {
t.Setenv("LOCAL_REGION", testConfig.RegionID)
ck, err := NewCockRoach(testConfig.V2GlobalDBURI, testConfig.V2LocalDBURI)
globalURI, localURI := requireCockroachTest(t)
ck, err := NewCockRoach(globalURI, localURI)
if err != nil {
t.Errorf("NewCockRoach() error = %v", err)
return
@@ -50,7 +42,8 @@ func TestCockroach_GetUserOauthProvider(t *testing.T) {
}
func TestCockroach_GetAccountWithWorkspace(t *testing.T) {
ck, err := NewCockRoach(os.Getenv("GLOBAL_COCKROACH_URI"), os.Getenv("LOCAL_COCKROACH_URI"))
globalURI, localURI := requireCockroachTest(t)
ck, err := NewCockRoach(globalURI, localURI)
if err != nil {
t.Errorf("NewCockRoach() error = %v", err)
return
@@ -66,8 +59,8 @@ func TestCockroach_GetAccountWithWorkspace(t *testing.T) {
}
func TestCockroach_InitTables(t *testing.T) {
t.Setenv("LOCAL_REGION", "")
ck, err := NewCockRoach("", "")
globalURI, localURI := requireCockroachTest(t)
ck, err := NewCockRoach(globalURI, localURI)
if err != nil {
t.Errorf("NewCockRoach() error = %v", err)
return
@@ -117,8 +110,8 @@ func TestCockroach_InitTables(t *testing.T) {
}
func TestCockroach_CreateCorporate(t *testing.T) {
t.Setenv("LOCAL_REGION", "")
ck, err := NewCockRoach("/", "")
globalURI, localURI := requireCockroachTest(t)
ck, err := NewCockRoach(globalURI, localURI)
if err != nil {
t.Errorf("NewCockRoach() error = %v", err)
return
@@ -138,3 +131,16 @@ func TestCockroach_CreateCorporate(t *testing.T) {
}
t.Logf("cor: %+v", cor)
}
func requireCockroachTest(t *testing.T) (string, string) {
t.Helper()
if os.Getenv("RUN_COCKROACH_TESTS") != "true" {
t.Skip("set RUN_COCKROACH_TESTS=true to run CockroachDB tests")
}
for _, name := range []string{"GLOBAL_COCKROACH_URI", "LOCAL_COCKROACH_URI", "LOCAL_REGION"} {
if os.Getenv(name) == "" {
t.Skipf("requires %s", name)
}
}
return os.Getenv("GLOBAL_COCKROACH_URI"), os.Getenv("LOCAL_COCKROACH_URI")
}
+26 -7
View File
@@ -66,6 +66,7 @@ func TestGenerateBillingDataPreservesTypedGroupKey(t *testing.T) {
}
func TestMongoDB_SaveBillingsWithAccountBalance(t *testing.T) {
requireMongoTest(t)
type fields struct {
URL string
Client *mongo.Client
@@ -285,6 +286,7 @@ func TestNewMongoInterface(t *testing.T) {
}
func TestMongoDB_GetBillingLastUpdateTime(t *testing.T) {
requireMongoTest(t)
dbCTX := context.Background()
m, err := NewMongoInterface(dbCTX, os.Getenv("MONGODB_URI"))
@@ -308,6 +310,7 @@ func TestMongoDB_GetBillingLastUpdateTime(t *testing.T) {
}
func TestMongoDB_DropMonitorCollectionsOlderThan(t *testing.T) {
requireMongoTest(t)
dbCTX := context.Background()
m, err := NewMongoInterface(dbCTX, os.Getenv("MONGODB_URI"))
if err != nil {
@@ -333,6 +336,7 @@ info generate billing data used {2 ns-7uyfrr47 pay-xy map[0:325 1:166 2:0]}
*/
func TestMongoDB_SetPropertyTypeLS(t *testing.T) {
requireMongoTest(t)
dbCTX := context.Background()
m, err := NewMongoInterface(dbCTX, os.Getenv("MONGODB_URI"))
@@ -360,6 +364,7 @@ func TestMongoDB_SetPropertyTypeLS(t *testing.T) {
}
func Test_mongoDB_GetDistinctMonitorCombinations(t *testing.T) {
requireMongoTest(t)
dbCTX := context.Background()
m, err := NewMongoInterface(dbCTX, os.Getenv("MONGODB_URI"))
@@ -383,6 +388,7 @@ func Test_mongoDB_GetDistinctMonitorCombinations(t *testing.T) {
}
func Test_mongoDB_CreateTTLTrafficTimeSeries(t *testing.T) {
requireMongoTest(t)
dbCTX := context.Background()
m, err := NewMongoInterface(dbCTX, os.Getenv("MONGODB_URI"))
@@ -402,6 +408,7 @@ func Test_mongoDB_CreateTTLTrafficTimeSeries(t *testing.T) {
}
func Test_mongoDB_SaveObjTraffic(t *testing.T) {
requireMongoTest(t)
dbCTX := context.Background()
m, err := NewMongoInterface(dbCTX, os.Getenv("MONGODB_URI"))
@@ -430,6 +437,7 @@ func Test_mongoDB_SaveObjTraffic(t *testing.T) {
}
func Test_mongoDB_GetAllLatestObjTraffic(t *testing.T) {
requireMongoTest(t)
dbCTX := context.Background()
m, err := NewMongoInterface(dbCTX, os.Getenv("MONGODB_URI"))
@@ -453,6 +461,7 @@ func Test_mongoDB_GetAllLatestObjTraffic(t *testing.T) {
}
func Test_mongoDB_HandlerTimeObjBucketSentTraffic(t *testing.T) {
requireMongoTest(t)
dbCTX := context.Background()
m, err := NewMongoInterface(dbCTX, os.Getenv("MONGODB_URI"))
@@ -476,11 +485,8 @@ func Test_mongoDB_HandlerTimeObjBucketSentTraffic(t *testing.T) {
t.Logf("handle time object bucket usage success: %v", bytes)
}
func init() {
os.Setenv("MONGODB_URI", "")
}
func Test_mongoDB_GetTimeObjBucketBucket(t *testing.T) {
requireMongoTest(t)
dbCTX := context.Background()
m, err := NewMongoInterface(dbCTX, os.Getenv("MONGODB_URI"))
@@ -504,9 +510,10 @@ func Test_mongoDB_GetTimeObjBucketBucket(t *testing.T) {
}
func Test_mongoDB_GetTimeUsedOwnerList(t *testing.T) {
requireMongoTest(t)
dbCTX := context.Background()
m, err := NewMongoInterface(dbCTX, "")
m, err := NewMongoInterface(dbCTX, os.Getenv("MONGODB_URI"))
if err != nil {
t.Errorf("failed to connect mongo: error = %v", err)
}
@@ -524,9 +531,10 @@ func Test_mongoDB_GetTimeUsedOwnerList(t *testing.T) {
}
func Test_mongoDB_GenerateBillingData(t *testing.T) {
requireMongoTest(t)
dbCTX := context.Background()
m, err := NewMongoInterface(dbCTX, os.Getenv("MONGO_URI"))
m, err := NewMongoInterface(dbCTX, os.Getenv("MONGODB_URI"))
if err != nil {
t.Errorf("failed to connect mongo: error = %v", err)
}
@@ -557,9 +565,10 @@ func Test_mongoDB_GenerateBillingData(t *testing.T) {
}
func Test_mongoDB_GetOwnersWithoutRecentUpdates(t *testing.T) {
requireMongoTest(t)
dbCTX := context.Background()
m, err := NewMongoInterface(dbCTX, "")
m, err := NewMongoInterface(dbCTX, os.Getenv("MONGODB_URI"))
if err != nil {
t.Errorf("failed to connect mongo: error = %v", err)
}
@@ -577,3 +586,13 @@ func Test_mongoDB_GetOwnersWithoutRecentUpdates(t *testing.T) {
}
t.Logf("get owners without recent updates success: %v", owners)
}
func requireMongoTest(t *testing.T) {
t.Helper()
if os.Getenv("RUN_MONGO_TESTS") != "true" {
t.Skip("set RUN_MONGO_TESTS=true to run MongoDB tests")
}
if os.Getenv("MONGODB_URI") == "" {
t.Skip("requires MONGODB_URI")
}
}
@@ -16,6 +16,7 @@ package mongo
import (
"context"
"os"
"strings"
"testing"
"time"
@@ -53,9 +54,10 @@ import (
//}
func Test_mongoDB_GetNamespaceTraffic(t *testing.T) {
requireMongoTest(t)
dbCTX := context.Background()
m, err := NewMongoInterface(dbCTX, "")
m, err := NewMongoInterface(dbCTX, os.Getenv("MONGODB_URI"))
if err != nil {
t.Errorf("failed to connect mongo: error = %v", err)
}
+2 -2
View File
@@ -43,8 +43,8 @@ vet: ## Run go vet against code.
go vet ./...
.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test ./... -coverprofile cover.out
test: ## Run tests.
go test -race ./... -count=1
##@ Deployment
@@ -23,13 +23,21 @@ import (
)
func TestGetUserObjectStorageFlow(t *testing.T) {
requireObjectStorageTest(t,
"MINIO_ENDPOINT",
"MINIO_ACCESS_KEY",
"MINIO_SECRET_KEY",
"PROM_URL",
"MINIO_USERNAME",
"MINIO_INSTANCE",
)
cli, err := NewOSClient(
os.Getenv("MINIO_ENDPOINT"),
os.Getenv("MINIO_ACCESS_KEY"),
os.Getenv("MINIO_SECRET_KEY"),
)
if err != nil {
t.Error(err)
t.Fatal(err)
}
start := time.Now().Truncate(time.Hour).Add(-time.Hour)
bytes, err := GetUserObjectStorageFlow(
@@ -41,7 +49,7 @@ func TestGetUserObjectStorageFlow(t *testing.T) {
start.Add(time.Hour),
)
if err != nil {
t.Error(err)
t.Fatal(err)
}
t.Log(ConvertBytes(bytes))
}
@@ -60,18 +68,23 @@ func ConvertBytes(bytes int64) string {
}
func TestQueryUserUsage(t *testing.T) {
requireObjectStorageTest(t,
"OBJECTSTORAGE_METRICS_ENDPOINT",
"OBJECTSTORAGE_METRICS_USERNAME",
"OBJECTSTORAGE_METRICS_PASSWORD",
)
obClient, err := NewMetricsClient(
"objectstorageapi.192.168.0.55.nip.io",
"username",
"passw0rd",
os.Getenv("OBJECTSTORAGE_METRICS_ENDPOINT"),
os.Getenv("OBJECTSTORAGE_METRICS_USERNAME"),
os.Getenv("OBJECTSTORAGE_METRICS_PASSWORD"),
false,
)
if err != nil {
t.Error(err)
t.Fatal(err)
}
metrics, err := QueryUserUsage(obClient)
if err != nil {
t.Error(err)
t.Fatal(err)
}
for _, metric := range metrics {
fmt.Println(metric)
@@ -79,18 +92,23 @@ func TestQueryUserUsage(t *testing.T) {
}
func TestQueryUserTraffic(t *testing.T) {
requireObjectStorageTest(t,
"OBJECTSTORAGE_METRICS_ENDPOINT",
"OBJECTSTORAGE_METRICS_USERNAME",
"OBJECTSTORAGE_METRICS_PASSWORD",
)
obClient, err := NewMetricsClient(
"objectstorageapi.192.168.0.55.nip.io",
"username",
"passw0rd",
os.Getenv("OBJECTSTORAGE_METRICS_ENDPOINT"),
os.Getenv("OBJECTSTORAGE_METRICS_USERNAME"),
os.Getenv("OBJECTSTORAGE_METRICS_PASSWORD"),
false,
)
if err != nil {
t.Error(err)
t.Fatal(err)
}
metrics, err := QueryUserUsageAndTraffic(obClient)
if err != nil {
t.Error(err)
t.Fatal(err)
}
for user, metric := range metrics {
@@ -100,3 +118,15 @@ func TestQueryUserTraffic(t *testing.T) {
fmt.Println("received:", metric.Received)
}
}
func requireObjectStorageTest(t *testing.T, envNames ...string) {
t.Helper()
if os.Getenv("RUN_OBJECTSTORAGE_TESTS") != "true" {
t.Skip("set RUN_OBJECTSTORAGE_TESTS=true to run object storage tests")
}
for _, name := range envNames {
if os.Getenv(name) == "" {
t.Skipf("requires %s", name)
}
}
}
+29 -52
View File
@@ -8,61 +8,19 @@ import (
"github.com/labring/sealos/controllers/pkg/account"
)
func setupenvAlipay() {
const (
envAppID = ""
envPrivateKey = ""
envAppCertPublicKey = ""
envRootCert = ""
envCertPublicKey = ""
)
// The following is only written if none of these variables are preset
if os.Getenv(account.AlipayAppID) == "" {
err := os.Setenv(account.AlipayAppID, envAppID)
if err != nil {
return
}
}
if os.Getenv(account.AlipayPrivateKey) == "" {
err := os.Setenv(account.AlipayPrivateKey, envPrivateKey)
if err != nil {
return
}
}
if os.Getenv(account.AlipayAppCertPublicKey) == "" {
err := os.Setenv(account.AlipayAppCertPublicKey, envAppCertPublicKey)
if err != nil {
return
}
}
if os.Getenv(account.AlipayRootCert) == "" {
err := os.Setenv(account.AlipayRootCert, envRootCert)
if err != nil {
return
}
}
if os.Getenv(account.AlipayCertPublicKey) == "" {
err := os.Setenv(account.AlipayCertPublicKey, envCertPublicKey)
if err != nil {
return
}
}
// sandboxEnvironment
err := os.Setenv(account.PayIsProduction, "true")
if err != nil {
return
}
}
// TestCreatePaymentIntegration test payment creation
func TestCreatePaymentIntegration(t *testing.T) {
requirePaymentTest(t,
account.AlipayAppID,
account.AlipayPrivateKey,
account.AlipayAppCertPublicKey,
account.AlipayRootCert,
account.AlipayCertPublicKey,
account.PayIsProduction,
)
ap, err := NewAlipayPayment()
if err != nil {
t.Skipf(
"Skip test: NewAlipayPayment failed, possibly because the sandbox was not fully configured%v",
err,
)
t.Fatalf("NewAlipayPayment() failed: %v", err)
}
// place an order of $1
tradeNo, qrURL, err := ap.CreatePayment(1_000_000, "test-user", "unit tests create payments")
@@ -74,7 +32,14 @@ func TestCreatePaymentIntegration(t *testing.T) {
// Full E2E Test: Payment → Inquiries → Refunds
func TestSandbox_EndToEnd(t *testing.T) {
setupenvAlipay()
requirePaymentTest(t,
account.AlipayAppID,
account.AlipayPrivateKey,
account.AlipayAppCertPublicKey,
account.AlipayRootCert,
account.AlipayCertPublicKey,
account.PayIsProduction,
)
ap, err := NewAlipayPayment()
if err != nil {
t.Fatalf("NewAlipayPayment() failed: %v", err)
@@ -117,3 +82,15 @@ func TestSandbox_EndToEnd(t *testing.T) {
}
t.Logf("the refund was successfulrefundNo=%s, refundFee=%s", refundNo, refundFee)
}
func requirePaymentTest(t *testing.T, envNames ...string) {
t.Helper()
if os.Getenv("RUN_PAYMENT_TESTS") != "true" {
t.Skip("set RUN_PAYMENT_TESTS=true to run payment provider tests")
}
for _, name := range envNames {
if os.Getenv(name) == "" {
t.Skipf("requires %s", name)
}
}
}
+9 -2
View File
@@ -15,15 +15,22 @@
package pay
import (
"os"
"testing"
)
func TestCreateCheckoutSession(t *testing.T) {
requirePaymentTest(t, StripeAPIKEY)
successURL := os.Getenv("STRIPE_TEST_SUCCESS_URL")
cancelURL := os.Getenv("STRIPE_TEST_CANCEL_URL")
if successURL == "" || cancelURL == "" {
t.Skip("requires STRIPE_TEST_SUCCESS_URL and STRIPE_TEST_CANCEL_URL")
}
stripe, err := CreateCheckoutSession(
2000,
"cny",
"http://localhost:8080",
"http://localhost:8080",
successURL,
cancelURL,
)
if err != nil {
t.Error(err)
+8 -58
View File
@@ -2,69 +2,19 @@ package pay
import (
"fmt"
"log"
"os"
"testing"
"time"
"github.com/labring/sealos/controllers/pkg/account"
)
func setupenvWechatpayment() {
// configure the environment variables of wechat pay
const (
envWechatPrivateKey = ""
envMchID = ""
envMchCertificateSerialNumber = ""
envMchAPIv3Key = ""
envAppID = ""
// envNotifyCallbackURL = "your_notify_callback_url_here" // 替换为你的支付通知回调URL
)
// check that the environment variables are set
if os.Getenv(MchID) == "" {
err := os.Setenv(MchID, envMchID)
if err != nil {
log.Fatalf("Failed to set the environment variable of WeChat merchant account: %v", err)
}
}
if os.Getenv(WechatPrivateKey) == "" {
err := os.Setenv(WechatPrivateKey, envWechatPrivateKey)
if err != nil {
log.Fatalf("Failed to set the environment variable for WeChat private key: %v", err)
}
}
if os.Getenv(MchCertificateSerialNumber) == "" {
err := os.Setenv(MchCertificateSerialNumber, envMchCertificateSerialNumber)
if err != nil {
log.Fatalf(
"Failed to set the environment variable of the serial number of the WeChat merchant certificate: %v",
err,
)
}
}
if os.Getenv(MchAPIv3Key) == "" {
err := os.Setenv(MchAPIv3Key, envMchAPIv3Key)
if err != nil {
log.Fatalf("Failed to set the environment variable of the WeChat API v3 key: %v", err)
}
}
if os.Getenv(AppID) == "" {
err := os.Setenv(AppID, envAppID)
if err != nil {
log.Fatalf("Failed to set the WeChat AppID environment variable: %v", err)
}
}
// sandboxEnvironment
err := os.Setenv(account.PayIsProduction, "true")
if err != nil {
return
}
}
func TestWechatPayment_PaymentAndRefund(t *testing.T) {
setupenvWechatpayment()
requirePaymentTest(t,
MchID,
WechatPrivateKey,
MchCertificateSerialNumber,
MchAPIv3Key,
AppID,
NotifyCallbackURL,
)
// initialize the wechat pay object
wechatPayment := WechatPayment{}
@@ -20,6 +20,9 @@ func setupTestDB(t *testing.T) *gorm.DB {
t.Helper()
// TODO need to set up a real test database
dsn := os.Getenv("TEST_DB_URI")
if dsn == "" {
t.Skip("requires TEST_DB_URI")
}
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
require.NoError(t, err)
+2 -2
View File
@@ -56,8 +56,8 @@ vet: ## Run go vet against code.
go vet ./...
.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) --arch=amd64 use $(ENVTEST_K8S_VERSION) -p path)" go test ./... -coverprofile cover.out
test: ## Run tests.
go test -race ./... -count=1
##@ Build
@@ -1,76 +0,0 @@
/*
Copyright 2023 sealos.
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 controllers
import (
"path/filepath"
"testing"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
)
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
var (
cfg *rest.Config
k8sClient client.Client
testEnv *envtest.Environment
)
func TestAPIs(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecsWithDefaultAndCustomReporters(t,
"Controller Suite",
[]Reporter{})
}
var _ = BeforeSuite(func() {
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
ErrorIfCRDPathMissing: false,
}
var err error
// cfg is defined in this file globally.
cfg, err = testEnv.Start()
Expect(err).NotTo(HaveOccurred())
Expect(cfg).NotTo(BeNil())
//+kubebuilder:scaffold:scheme
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
Expect(err).NotTo(HaveOccurred())
Expect(k8sClient).NotTo(BeNil())
}, 60)
var _ = AfterSuite(func() {
By("tearing down the test environment")
err := testEnv.Stop()
Expect(err).NotTo(HaveOccurred())
})
+5 -3
View File
@@ -6,7 +6,7 @@ LICENSE_KEY ?=
CONTROLLER_LICENSE_PKG=github.com/labring/sealos/controllers/pkg/license
# ENVTEST_K8S_VERSION refers to the version of kubebuilder assets to be downloaded by envtest binary.
ENVTEST_K8S_VERSION = 1.25.6
ENVTEST_K8S_VERSION = 1.25.0
# Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
ifeq (,$(shell go env GOBIN))
@@ -61,8 +61,10 @@ vet: ## Run go vet against code.
go vet ./...
.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test ./... -coverprofile cover.out
test: envtest ## Run tests.
@LD_FLAGS=""; \
[ -n "$(LICENSE_KEY)" ] && LD_FLAGS="-X ${CONTROLLER_LICENSE_PKG}.encryptionKey=${LICENSE_KEY}"; \
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" go test -race -ldflags "$${LD_FLAGS}" ./... -count=1
##@ Build
@@ -36,6 +36,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/envtest"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
"sigs.k8s.io/controller-runtime/pkg/webhook"
)
// These tests use Ginkgo (BDD-style Go testing framework). Refer to
@@ -98,7 +99,11 @@ var _ = BeforeSuite(func() {
mgr, err := ctrl.NewManager(cfg, ctrl.Options{
Scheme: scheme,
LeaderElection: false,
// MetricsBindAddress: "0",
WebhookServer: webhook.NewServer(webhook.Options{
Host: webhookInstallOptions.LocalServingHost,
Port: webhookInstallOptions.LocalServingPort,
CertDir: webhookInstallOptions.LocalServingCertDir,
}),
})
Expect(err).NotTo(HaveOccurred())
@@ -50,6 +50,9 @@ var (
)
func TestUtils(t *testing.T) {
if os.Getenv("RUN_KUBECONFIG_CLUSTER_TESTS") != "true" {
t.Skip("set RUN_KUBECONFIG_CLUSTER_TESTS=true to run kubeconfig cluster tests")
}
RegisterFailHandler(Fail)
RunSpecs(t, "run helper suite")
+3 -1
View File
@@ -57,7 +57,7 @@ var _ = BeforeSuite(func() {
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
By("bootstrapping test environment")
useExisting := true
useExisting := false
if val := os.Getenv("USE_EXISTING_CLUSTER"); val != "" {
if parsed, err := strconv.ParseBool(val); err == nil {
useExisting = parsed
@@ -149,6 +149,7 @@ clusters:
contexts:
- context:
cluster: sealos
namespace: ns-f8699ded-58d3-432b-a9ff-56568b57a38d
user: f8699ded-58d3-432b-a9ff-56568b57a38d
name: f8699ded-58d3-432b-a9ff-56568b57a38d@sealos
current-context: f8699ded-58d3-432b-a9ff-56568b57a38d@sealos
@@ -157,6 +158,7 @@ preferences: {}
users:
- name: f8699ded-58d3-432b-a9ff-56568b57a38d
user:
token: test-token
client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURTRENDQWpDZ0F3SUJBZ0lRYldZeDZSS3dOQ1M5L29oQTArMkZ4ekFOQmdrcWhraUc5dzBCQVFzRkFEQVYKTVJNd0VRWURWUVFERXdwcmRXSmxjbTVsZEdWek1CNFhEVEl5TURneU1EQTFNalkxT0ZvWERUSXlNRGd5TURBMgpNekUxT0Zvd0x6RXRNQ3NHQTFVRUF4TWtaamcyT1Rsa1pXUXROVGhrTXkwME16SmlMV0U1Wm1ZdE5UWTFOamhpCk5UZGhNemhrTUlJQklqQU5CZ2txaGtpRzl3MEJBUUVGQUFPQ0FROEFNSUlCQ2dLQ0FRRUEzQmRFa0VFNy9tTjQKWllTUkIvSW5JSGpMeW9DNHZKeUUreHM2bkczdXc3VjROdm1ia0ROSU9uS2cvQW9uNE1TNWhHbHJ1S0VydnJWSQo0L0pjTnFNMXFxTTVWVWVMRXVjVzU3cXE3QkdDbmZQSW9ndEd1YmpZRTJpWXhhYU8ySFVuSHF0VWNUajZDbTd1Ck1PWVA2di9tMkRZWjNxTDdjYTRjc1MzcVp1aW5oTG5ML1hJQXMwZUg3SmRnQkJISW1aVUlrRW9ueUNvNzI5VGkKZkFEdWhiQjZ1REtiRmFsMlAwQzZ5a1ltU2VVNHVHaytXQ0pDeDF2Nkd5THIzWXo1cHh6bXd4ck5CUUF2d2hYTwpQMFczVUZ1Rnc5MGlwQTN1dXpaT09aakxpd2U1N1ZnT1ZxbFFpMGY4SFFmYWRBUU8vTnFVc1lTQTk5K2ZzSXFoClJWK3Z5RUtITndJREFRQUJvM293ZURBT0JnTlZIUThCQWY4RUJBTUNCYUF3RXdZRFZSMGxCQXd3Q2dZSUt3WUIKQlFVSEF3SXdEQVlEVlIwVEFRSC9CQUl3QURBZkJnTlZIU01FR0RBV2dCUWlZVWxPUVBYdnYwZGhUaUxyMGFqMApxemhiY1RBaUJnTlZIUkVFR3pBWmdoZGhjR2x6WlhKMlpYSXVZMngxYzNSbGNpNXNiMk5oYkRBTkJna3Foa2lHCjl3MEJBUXNGQUFPQ0FRRUFsK1BSN1NHVVZMdjQ0bC9mY1ducHJqcFZpanM2eGJpSm9mVGNSL0JaSnRGaWpTWjEKNlRJU0t1c3hjb2lzZE16M1dsVWsyREpPYlJVV2FKamY4VXRUdkZmR0Z3UEJHU1k5aGxtR0NENEpVeXJHWVBzawoyby9jTGVDVVRWQzJvd2FPOXVyRTdmOGR4eU4xMHliaGhaZ1BuM0xDUGtiL0hCTFNJWFNFcWxwd0NmeURaMXFHCkJMbkVpa2VuVnJXc1FHSVJ1Mk91WkJINjYyU1VjMkk5SHlHemorTm1UamRES1VHNnZHdkw3WGdJdlgreWhjTDMKcVBsbFR1aFlab0lZdkErS1p1MFdFQWoyQWkvVU5MU21IbktyQkF6bm1qeXVGY2JFZFpYZDFSVGQycytWd0FFSgoxMnVHbXhIank2WCsvb0NxY0d6ZXJYUVRDSmVGWi8wWTBVMFl4UT09Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBM0JkRWtFRTcvbU40WllTUkIvSW5JSGpMeW9DNHZKeUUreHM2bkczdXc3VjROdm1iCmtETklPbktnL0FvbjRNUzVoR2xydUtFcnZyVkk0L0pjTnFNMXFxTTVWVWVMRXVjVzU3cXE3QkdDbmZQSW9ndEcKdWJqWUUyaVl4YWFPMkhVbkhxdFVjVGo2Q203dU1PWVA2di9tMkRZWjNxTDdjYTRjc1MzcVp1aW5oTG5ML1hJQQpzMGVIN0pkZ0JCSEltWlVJa0VvbnlDbzcyOVRpZkFEdWhiQjZ1REtiRmFsMlAwQzZ5a1ltU2VVNHVHaytXQ0pDCngxdjZHeUxyM1l6NXB4em13eHJOQlFBdndoWE9QMFczVUZ1Rnc5MGlwQTN1dXpaT09aakxpd2U1N1ZnT1ZxbFEKaTBmOEhRZmFkQVFPL05xVXNZU0E5OStmc0lxaFJWK3Z5RUtITndJREFRQUJBb0lCQUdDVHZUeG53OEd2T0dlagpzbGlBUS9jVnlxZERzTXpqQ2Q5K1pVdTdXYWg3ZXhMMG1QUy83QlBwdFFha0ZqZWxXNXJrLzZYMjQxRStENHduCkQ1dlNKbnlJUDJKU2tJNXM1VG91U1U1cHFKMVRHbGt4QlluOXVLTmJwSjRtcGt3SnJHN2kwNTBUV1hVMmxFTFUKMFd0WGU1Nm9ydFZwUTFqeEJCb2pnZFpDaFMvUjMzM2dnUW9uRFI4NGx2aDc2cC9zM2x4MHFPbUE4K25nbURJdwpyUGdobzBuOFhVZFFaUDk0alYzVlREcklZNHFOZFlYbzRsODZqUUozTHhndkp4YzV2MUJuUk9MYXJ0N2FaR01iCnB6VzhsRXpKd2pkYlFiQ1hGRkc4bXFZTU42RkREaGl1YmRnb1h6dUd5RXNobSswRVk4clpOcWxhVzcvc0lzNjkKcUIxa0VqRUNnWUVBOFh3OWtjbjVBbGhEbnQ3SEg5bUszeUZ4TTU5Q3BRZVA0b0FPWXJuOFNZSkpvRTdzU1dvVwpXZmFmTmFBVnFQL3lCZFFnUTdSbFZYTlVSdHVibXN0MW5JKzFnbTJVQ0tEQ1VuWGR2Ylp1eHZiYnFSdlJXc0EyCmdTNG03eVBoR1hDb1lVMzhHQy9qcXB3UmFHMnVHWFp5T1M0TjVDN1lBUDMyMWpKNEp6cExzWHNDZ1lFQTZWSFUKUDlDS2VUUVFuV2RzdFRiVXJVYVZpVjhadGo3U0JkRWFtQnZWUnRoeGluU1QzaCtmOGxuaTY1czVXUzNvZUQycApYZW5oeXZwWDkvOFhrT2FtRXdzZVVHNFdCVk16Y1kzVm9CdDNlTVE2WGRaaHgwOWRRek5zZXhUMkN4bTZHTWpUCjV5cXR6TUtOTVBoOFB0cGlsUFNHbytKSXdRVkxaWkVnK24wNkhuVUNnWUVBbmttLzJlWTRFSzltYzZhM2cwc0gKV2tjRGVzRHo0RlRhbmE4dXZzd0djUEN6N2g2TmgzbkFlT3ZOWkVzd3AzeE5Xa0MzZldtcjJwMGtLdVljVXhUMgpYTTllUE1ZeStJelhrMUdyTFlWOWkzR1lmbnE3ZWU3d1N6RERXSkYrSlR6UlFpYnFEYmltVk5qRUdGMThkemhLCm11eHpNcFQ2Qlh4eTVlaGpGZU9DWmkwQ2dZRUFsR2RVL3FZUmZkaE0vU0ZzdHJMQ2dkaFVnd1QzWU1FQ2EycSsKWktQSGU0RnVicWVKNmczcGVZZ00ydGxubDc2b2o5cUFvTmlEb3N5cktYV2FzckxTVFdpVUJvcU8vU0lYcFpHVwpvSGozKzl1c1dFVmsraFlUOXd0OVk2aEllM1VJdG56K3M1bWs1SW1XcnVCT2Z0Zi9Qa2x1WGswdkEzN3ZueEc1CmpUb2J2b1VDZ1lFQTUvUDhBc1kzdjVVL24yUk5EWWczNEJPN1Awb3ZDVHo5V09TMmkybHBIcUxqMGR4V2RPUjcKU1VpNVN1UDBFK1RQODNwRGo3R3l0NVVVYmRaKys5RU4xMll2cHVxUmpIM3NMRFo3Qi8xN0tocWk3QVRIRExLcwpDalp4YmpQRlA5RUduUkxqbXJHaFd0YTlzaUN0YXhyb3ZlbVk4ME5rK2V1STBNQ1oyMklGZFdRPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
`
@@ -17,6 +17,7 @@ package licensegate
import (
"context"
"encoding/base64"
"os"
"testing"
"time"
@@ -35,6 +36,9 @@ func newTestLicense(
activationTime time.Time,
) *licensev1.License {
t.Helper()
if os.Getenv("LICENSE_KEY") == "" {
t.Skip("requires LICENSE_KEY to sign test licenses")
}
decodeKey, err := base64.StdEncoding.DecodeString(licensepkg.GetEncryptionKey())
if err != nil {
t.Fatalf("decode encryption key failed: %v", err)
@@ -130,6 +134,8 @@ func TestRefreshUsesLatestActiveLicense(t *testing.T) {
}
older := newTestLicense(t, 5, licensev1.LicenseStatusPhaseActive, time.Now().Add(-time.Hour))
newer := newTestLicense(t, 20, licensev1.LicenseStatusPhaseActive, time.Now())
older.Name = "older-license"
newer.Name = "newer-license"
client := fake.NewClientBuilder().WithScheme(scheme).WithObjects(older, newer).Build()
if err := Refresh(context.Background(), client); err != nil {
t.Fatalf("refresh failed: %v", err)
+14 -2
View File
@@ -1,6 +1,7 @@
package api
import (
"os"
"testing"
"time"
@@ -9,12 +10,23 @@ import (
)
func Test_getCreditsInfo(t *testing.T) {
if os.Getenv("RUN_ACCOUNT_EXTERNAL_TESTS") != "true" {
t.Skip("set RUN_ACCOUNT_EXTERNAL_TESTS=true to run account external tests")
}
for _, name := range []string{"GLOBAL_COCKROACH_URI", "LOCAL_COCKROACH_URI", "LOCAL_REGION"} {
if os.Getenv(name) == "" {
t.Skipf("requires %s", name)
}
}
userUID, err := uuid.Parse("03c7ef29-4556-4f5d-a54b-969f315658a3")
if err != nil {
t.Fatalf("failed to parse UUID: %v", err)
}
t.Setenv("LOCAL_REGION", "")
dao.DBClient, err = dao.NewAccountForTest("", "", "")
dao.DBClient, err = dao.NewAccountForTest(
"",
os.Getenv("GLOBAL_COCKROACH_URI"),
os.Getenv("LOCAL_COCKROACH_URI"),
)
if err != nil {
t.Fatalf("failed to create DB client: %v", err)
}
+39 -9
View File
@@ -13,6 +13,7 @@ import (
)
func TestCockroach_GetPayment(t *testing.T) {
requireAccountDAOExternalTest(t, "GLOBAL_COCKROACH_URI", "LOCAL_COCKROACH_URI", "LOCAL_REGION")
db, err := newAccountForTest(
"",
os.Getenv("GLOBAL_COCKROACH_URI"),
@@ -35,6 +36,7 @@ func TestCockroach_GetPayment(t *testing.T) {
}
func TestMongoDB_GetAppCosts(t *testing.T) {
requireAccountDAOExternalTest(t, "MONGO_URI")
db, err := newAccountForTest(os.Getenv("MONGO_URI"), "", "")
if err != nil {
t.Fatalf("NewAccountInterface() error = %v", err)
@@ -66,7 +68,7 @@ func TestMongoDB_GetAppCosts(t *testing.T) {
}
func TestCockroach_GetTransfer(t *testing.T) {
t.Setenv("LOCAL_REGION", "97925cb0-c8e2-4d52-8b39-d8bf0cbb414a")
requireAccountDAOExternalTest(t, "GLOBAL_COCKROACH_URI", "LOCAL_COCKROACH_URI", "LOCAL_REGION")
db, err := newAccountForTest(
"",
@@ -103,6 +105,7 @@ func TestCockroach_GetTransfer(t *testing.T) {
}
func TestMongoDB_GetCostAppList(t *testing.T) {
requireAccountDAOExternalTest(t, "MONGO_URI")
dbCTX := context.Background()
m, err := newAccountForTest(os.Getenv("MONGO_URI"), "", "")
if err != nil {
@@ -142,6 +145,7 @@ func TestMongoDB_GetCostAppList(t *testing.T) {
}
func TestMongoDB_GetCostOverview(t *testing.T) {
requireAccountDAOExternalTest(t, "MONGO_URI")
dbCTX := context.Background()
m, err := newAccountForTest(os.Getenv("MONGO_URI"), "", "")
if err != nil {
@@ -340,6 +344,7 @@ func TestUnmarshal_Config(t *testing.T) {
}
func TestMongoDB_GetBasicCostDistribution(t *testing.T) {
requireAccountDAOExternalTest(t, "MONGO_URI")
dbCTX := context.Background()
m, err := newAccountForTest(os.Getenv("MONGO_URI"), "", "")
if err != nil {
@@ -373,6 +378,7 @@ func TestMongoDB_GetBasicCostDistribution(t *testing.T) {
}
func TestMongoDB_GetAppCostTimeRange(t *testing.T) {
requireAccountDAOExternalTest(t, "MONGO_URI")
dbCTX := context.Background()
m, err := newAccountForTest(os.Getenv("MONGO_URI"), "", "")
if err != nil {
@@ -407,6 +413,7 @@ func TestMongoDB_GetAppCostTimeRange(t *testing.T) {
}
func TestMongoDB_GetConsumptionAmount(t *testing.T) {
requireAccountDAOExternalTest(t, "MONGO_URI")
dbCTX := context.Background()
m, err := newAccountForTest(os.Getenv("MONGO_URI"), "", "")
if err != nil {
@@ -467,6 +474,7 @@ func TestMongoDB_GetConsumptionAmount(t *testing.T) {
}
func TestMongoDB_GetAppCost1(t *testing.T) {
requireAccountDAOExternalTest(t, "MONGO_URI")
dbCTX := context.Background()
m, err := newAccountForTest(os.Getenv("MONGO_URI"), "", "")
if err != nil {
@@ -542,6 +550,13 @@ func TestMongoDB_GetAppCost1(t *testing.T) {
}
func TestAccount_ApplyInvoice(t *testing.T) {
requireAccountDAOExternalTest(
t,
"MONGO_URI",
"GLOBAL_COCKROACH_URI",
"LOCAL_COCKROACH_URI",
"LOCAL_REGION",
)
dbCTX := context.Background()
m, err := newAccountForTest(
os.Getenv("MONGO_URI"),
@@ -598,6 +613,13 @@ func TestAccount_ApplyInvoice(t *testing.T) {
}
func TestAccount_SetStatusInvoice(t *testing.T) {
requireAccountDAOExternalTest(
t,
"MONGO_URI",
"GLOBAL_COCKROACH_URI",
"LOCAL_COCKROACH_URI",
"LOCAL_REGION",
)
dbCTX := context.Background()
m, err := newAccountForTest(
os.Getenv("MONGO_URI"),
@@ -623,6 +645,7 @@ func TestAccount_SetStatusInvoice(t *testing.T) {
}
func TestAccount_UseGiftCode(t *testing.T) {
requireAccountDAOExternalTest(t, "GLOBAL_COCKROACH_URI", "LOCAL_COCKROACH_URI", "LOCAL_REGION")
db, err := newAccountForTest(
"",
os.Getenv("GLOBAL_COCKROACH_URI"),
@@ -649,6 +672,7 @@ func TestAccount_UseGiftCode(t *testing.T) {
}
func TestAccount_GetUserRealNameInfo(t *testing.T) {
requireAccountDAOExternalTest(t, "GLOBAL_COCKROACH_URI", "LOCAL_COCKROACH_URI", "LOCAL_REGION")
db, err := newAccountForTest(
"",
os.Getenv("GLOBAL_COCKROACH_URI"),
@@ -674,6 +698,7 @@ func TestAccount_GetUserRealNameInfo(t *testing.T) {
}
func TestAccount_GetEnterpriseRealNameInfo(t *testing.T) {
requireAccountDAOExternalTest(t, "GLOBAL_COCKROACH_URI", "LOCAL_COCKROACH_URI", "LOCAL_REGION")
db, err := newAccountForTest(
"",
os.Getenv("GLOBAL_COCKROACH_URI"),
@@ -698,15 +723,8 @@ func TestAccount_GetEnterpriseRealNameInfo(t *testing.T) {
t.Logf("enterpriseRealNameInfo = %+v", enterpriseRealNameInfo)
}
func init() {
// set env
os.Setenv("MONGO_URI", "")
os.Setenv("GLOBAL_COCKROACH_URI", "")
os.Setenv("LOCAL_COCKROACH_URI", "")
os.Setenv("LOCAL_REGION", "")
}
func TestMongoDB_GetMonitorUniqueValues(t *testing.T) {
requireAccountDAOExternalTest(t, "MONGO_URI")
db, err := newAccountForTest(os.Getenv("MONGO_URI"), "", "")
if err != nil {
t.Fatalf("NewAccountInterface() error = %v", err)
@@ -726,6 +744,18 @@ func TestMongoDB_GetMonitorUniqueValues(t *testing.T) {
}
}
func requireAccountDAOExternalTest(t *testing.T, envNames ...string) {
t.Helper()
if os.Getenv("RUN_ACCOUNT_EXTERNAL_TESTS") != "true" {
t.Skip("set RUN_ACCOUNT_EXTERNAL_TESTS=true to run account external tests")
}
for _, name := range envNames {
if os.Getenv(name) == "" {
t.Skipf("requires %s", name)
}
}
}
func TestAccount_ReconcileUnsettledLLMBilling(t *testing.T) {
type fields struct {
MongoDB *MongoDB
@@ -4,7 +4,6 @@ import (
"context"
"fmt"
"net"
"os"
"testing"
"time"
@@ -22,12 +21,11 @@ const (
workspaceConsumptionTestDB = "workspace-consumption-test"
workspaceConsumptionTestColl = "billing"
workspaceConsumptionBenchmarkRecords = 10000
workspaceConsumptionRequiredEnv = "TESTCONTAINERS_REQUIRED"
)
func newWorkspaceConsumptionMongo(tb testing.TB) (*MongoDB, context.Context) {
tb.Helper()
skipIfWorkspaceConsumptionDockerIsNotHealthy(tb)
requireWorkspaceConsumptionDocker(tb)
ctx := context.Background()
container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
@@ -91,37 +89,25 @@ func newWorkspaceConsumptionMongo(tb testing.TB) (*MongoDB, context.Context) {
return mongoDB, ctx
}
func skipIfWorkspaceConsumptionDockerIsNotHealthy(tb testing.TB) {
func requireWorkspaceConsumptionDocker(tb testing.TB) {
tb.Helper()
defer func() {
if r := recover(); r != nil {
skipOrFailWorkspaceConsumptionDockerf(
tb,
"recovered from panic: %v; Docker is not running",
r,
)
tb.Fatalf("recovered from panic while checking Docker: %v", r)
}
}()
ctx := context.Background()
provider, err := testcontainers.ProviderDocker.GetProvider()
if err != nil {
skipOrFailWorkspaceConsumptionDockerf(tb, "Docker is not running: %v", err)
tb.Fatalf("get Docker provider: %v", err)
}
defer provider.Close()
if err := provider.Health(ctx); err != nil {
skipOrFailWorkspaceConsumptionDockerf(tb, "Docker is not running: %v", err)
tb.Fatalf("check Docker health: %v", err)
}
}
func skipOrFailWorkspaceConsumptionDockerf(tb testing.TB, format string, args ...any) {
tb.Helper()
if os.Getenv(workspaceConsumptionRequiredEnv) == "true" {
tb.Fatalf(format, args...)
}
tb.Skipf(format, args...)
}
func TestGetWorkspaceConsumptionAmountWithMongoRuntime(t *testing.T) {
mongoDB, ctx := newWorkspaceConsumptionMongo(t)
startTime := time.Date(2026, time.January, 1, 0, 0, 0, 0, time.UTC)
+20 -9
View File
@@ -8,16 +8,25 @@ import (
"net/http"
"os"
"testing"
"time"
"github.com/labring/sealos/service/account/helper"
)
func Test_Auth(t *testing.T) {
host := "http://localhost:2333"
if os.Getenv("RUN_ACCOUNT_EXTERNAL_TESTS") != "true" {
t.Skip("set RUN_ACCOUNT_EXTERNAL_TESTS=true to run account external tests")
}
host := os.Getenv("ACCOUNT_TEST_API_URL")
kubeConfigPath := os.Getenv("ACCOUNT_TEST_KUBECONFIG")
if host == "" || kubeConfigPath == "" {
t.Skip("requires ACCOUNT_TEST_API_URL and ACCOUNT_TEST_KUBECONFIG")
}
url := host + helper.GROUP + helper.GetProperties
kubeConfig, err := os.ReadFile("./kubeconfig")
// #nosec G703 -- the operator explicitly supplies the test kubeconfig path.
kubeConfig, err := os.ReadFile(kubeConfigPath)
if err != nil {
t.Errorf("failed to read kubeconfig: %v", err)
t.Fatalf("failed to read kubeconfig: %v", err)
}
requestBody := map[string]any{
@@ -29,10 +38,10 @@ func Test_Auth(t *testing.T) {
jsonValue, err := json.Marshal(requestBody)
if err != nil {
t.Errorf("failed to marshal request body: %v", err)
t.Fatalf("failed to marshal request body: %v", err)
}
// #nosec G107
// #nosec G704 -- the operator explicitly enables and configures this external test.
request, err := http.NewRequestWithContext(
context.Background(),
http.MethodPost,
@@ -40,19 +49,21 @@ func Test_Auth(t *testing.T) {
bytes.NewBuffer(jsonValue),
)
if err != nil {
t.Errorf("failed to create request: %v", err)
t.Fatalf("failed to create request: %v", err)
}
request.Header.Set("Content-Type", "application/json")
response, err := http.DefaultClient.Do(request)
client := &http.Client{Timeout: 30 * time.Second}
// #nosec G704 -- the operator explicitly enables and configures this external test.
response, err := client.Do(request)
if err != nil {
t.Errorf("failed to post request: %v", err)
t.Fatalf("failed to post request: %v", err)
}
defer response.Body.Close()
responseBody := new(bytes.Buffer)
_, err = responseBody.ReadFrom(response.Body)
if err != nil {
t.Errorf("failed to read response body: %v", err)
t.Fatalf("failed to read response body: %v", err)
}
fmt.Println("Response:", response.Status)
fmt.Println("Body:", responseBody.String())
+2 -2
View File
@@ -58,8 +58,8 @@ vet: ## Run go vet against code.
go vet ./...
.PHONY: test
test: manifests generate fmt vet envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) --arch=amd64 use $(ENVTEST_K8S_VERSION) -p path)" go test ./... -coverprofile cover.out
test: ## Run tests.
go test -race ./... -count=1 -coverprofile cover.out -covermode=atomic
##@ Build
+3 -3
View File
@@ -60,8 +60,8 @@ vet: ## Run go vet against code.
go vet ./...
.PHONY: test
test: manifests generate fmt vet setup-envtest ## Run tests.
KUBEBUILDER_ASSETS="$(shell "$(ENVTEST)" use $(ENVTEST_K8S_VERSION) --bin-dir "$(LOCALBIN)" -p path)" go test $$(go list ./... | grep -v /e2e) -coverprofile cover.out
test: ## Run tests.
go test -race $$(go list ./... | grep -v /e2e) -count=1 -coverprofile cover.out -covermode=atomic
# TODO(user): To use a different vendor for e2e tests, modify the setup under 'tests/e2e'.
# The default setup assumes Kind is pre-installed and builds/loads the Manager Docker image locally.
@@ -85,7 +85,7 @@ setup-test-e2e: ## Set up a Kind cluster for e2e tests if it does not exist
.PHONY: test-e2e
test-e2e: setup-test-e2e manifests generate fmt vet ## Run the e2e tests. Expected an isolated environment using Kind.
KIND=$(KIND) KIND_CLUSTER=$(KIND_CLUSTER) go test -tags=e2e ./test/e2e/ -v -ginkgo.v
KIND=$(KIND) KIND_CLUSTER=$(KIND_CLUSTER) go test -race -tags=e2e ./test/e2e/ -v -ginkgo.v
$(MAKE) cleanup-test-e2e
.PHONY: cleanup-test-e2e