98 lines
3.6 KiB
Go
98 lines
3.6 KiB
Go
//go:build integration
|
|
|
|
package postgresql_test
|
|
|
|
import (
|
|
"context"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
"git.ddupan.top/panxiao81/ayatori/internal/database/adapter/kubernetes"
|
|
"git.ddupan.top/panxiao81/ayatori/internal/database/application"
|
|
databasecontroller "git.ddupan.top/panxiao81/ayatori/internal/database/controller"
|
|
"git.ddupan.top/panxiao81/ayatori/internal/database/domain/instance"
|
|
"git.ddupan.top/panxiao81/ayatori/internal/database/domain/provisioning"
|
|
"k8s.io/apimachinery/pkg/api/meta"
|
|
ctrl "sigs.k8s.io/controller-runtime"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
controllerconfig "sigs.k8s.io/controller-runtime/pkg/config"
|
|
metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
|
|
)
|
|
|
|
func testProvisioningManager(t *testing.T, f *provisioningFixture) {
|
|
t.Helper()
|
|
database := f.bound(t, "watch_supply")
|
|
// 首次 list/watch 自动供应;第二个新 manager 只观察确认记录,不重新建库。
|
|
var roleOID, databaseOID int64
|
|
for range 2 {
|
|
skipRepeatedName := true
|
|
manager, err := ctrl.NewManager(f.config, ctrl.Options{Scheme: f.scheme, Metrics: metricsserver.Options{BindAddress: "0"}, HealthProbeBindAddress: "0",
|
|
Controller: controllerconfig.Controller{SkipNameValidation: &skipRepeatedName}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
resources := &kubernetes.ProvisioningResources{Client: manager.GetClient(), Reader: manager.GetAPIReader()}
|
|
backend := &countProvisioningObservations{ProvisioningBackend: f.service}
|
|
service := &application.DatabaseReconciliation{
|
|
Credentials: &application.CredentialPreparation{Resources: &kubernetes.CredentialResources{Client: manager.GetClient(), Reader: manager.GetAPIReader()}, Store: f.store},
|
|
Provisioning: &application.DatabaseProvisioning{Resources: resources, Credentials: f.store, Backend: backend},
|
|
}
|
|
if err := databasecontroller.NewProvisioningReconciler(manager.GetClient(), service).SetupWithManager(manager); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
ctx, stop := context.WithCancel(f.ctx)
|
|
done := make(chan error, 1)
|
|
go func() { done <- manager.Start(ctx) }()
|
|
// 使用 scope 确保任何失败都先停止 worker,再由 fixture 关闭共享连接。
|
|
func() {
|
|
defer func() {
|
|
stop()
|
|
select {
|
|
case err := <-done:
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
case <-time.After(10 * time.Second):
|
|
t.Error("供应 manager 未停止")
|
|
}
|
|
}()
|
|
if !manager.GetCache().WaitForCacheSync(ctx) {
|
|
t.Fatal("供应 cache 未同步")
|
|
}
|
|
deadline := time.After(15 * time.Second)
|
|
for {
|
|
if err := f.api.Get(f.ctx, client.ObjectKeyFromObject(database), database); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if meta.IsStatusConditionTrue(database.Status.Conditions, "ResourcesReady") && backend.reads.Load() > 0 {
|
|
break
|
|
}
|
|
select {
|
|
case <-deadline:
|
|
t.Fatal("watch 未推动资源创建")
|
|
case <-time.After(100 * time.Millisecond):
|
|
}
|
|
}
|
|
if roleOID != 0 && (roleOID != database.Status.RoleOID || databaseOID != database.Status.DatabaseOID) {
|
|
t.Fatal("manager 重启替换已确认资源")
|
|
}
|
|
roleOID, databaseOID = database.Status.RoleOID, database.Status.DatabaseOID
|
|
}()
|
|
}
|
|
f.status(t, database, provisioning.Available)
|
|
}
|
|
|
|
type countProvisioningObservations struct {
|
|
application.ProvisioningBackend
|
|
reads atomic.Int32
|
|
}
|
|
|
|
func (b *countProvisioningObservations) InspectResources(ctx context.Context, target instance.ObservationTarget, name, role string) (provisioning.Observation, error) {
|
|
observation, err := b.ProvisioningBackend.InspectResources(ctx, target, name, role)
|
|
if err == nil && name == "watch_supply" {
|
|
b.reads.Add(1)
|
|
}
|
|
return observation, err
|
|
}
|