package cloudtoedge import ( "fmt" "net/http" "strings" "testing" "cloud.google.com/go/pubsub" dsapi "edge-infra.dev/pkg/edge/datasync/apis/v1alpha1" "edge-infra.dev/pkg/edge/datasync/couchdb" "edge-infra.dev/pkg/k8s/testing/kmp" "edge-infra.dev/test/f2" "edge-infra.dev/test/f2/x/ktest" "gotest.tools/v3/assert" "gotest.tools/v3/assert/cmp" "gotest.tools/v3/poll" corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" ) func TestDBCreationAndDeletion(t *testing.T) { feature := f2.NewFeature("Datasync DB Creation And Deletion"). Test("Create New Database", func(ctx f2.Context, t *testing.T) f2.Context { result := pubSubClient.Topic(pubSubTopic).Publish(ctx, &pubsub.Message{ Attributes: map[string]string{ "tenant_id": bslInfo.OrganizationID, "db_name": fmt.Sprintf("db-%s", ctx.RunID), "entity_id": ctx.RunID, "entity_type": "json", }, Data: tlog, }) msgID, err := result.Get(ctx) assert.NilError(t, err, "fail to send C2E message to pub/sub") t.Log("Sent pub/sub message Id:", msgID) return ctx }). Test("Verify DB Exists In The Cloud", func(ctx f2.Context, t *testing.T) f2.Context { k := ktest.FromContextT(ctx, t) secret := corev1.Secret{} key := client.ObjectKey{Namespace: "couchctl", Name: couchdb.StoreReplicationSecretName} err := k.Client.Get(ctx, key, &secret) assert.NilError(t, err, "fail to get couchdb master secret") req, err := couchDBRequest(secret, string(secret.Data["uri"]), fmt.Sprintf("db-%s", ctx.RunID), ctx.RunID) assert.NilError(t, err, "fail to create couchdb request") var resp *http.Response poll.WaitOn(t, func(_ poll.LogT) poll.Result { resp, err = http.DefaultClient.Do(req) if err == nil && resp.StatusCode == 200 { return poll.Success() } return poll.Continue("fail to confirm existence of docs from couchdb master: %s", errMessage(resp, req, err)) }, poll.WithDelay(k.Tick), poll.WithTimeout(k.Timeout*timeoutMultiplier)) return ctx }). Test("Verify Replication Is Successful", func(ctx f2.Context, t *testing.T) f2.Context { k := ktest.FromContextT(ctx, t) replications := dsapi.CouchDBReplicationSetList{} err := k.Client.List(ctx, &replications, client.InNamespace(couchNamespace)) assert.NilError(t, err, "fail to list couchdb replications") assert.Check(t, cmp.Len(replications.Items, len(nodes.Items)), "number of couchdb replications not equal to number of nodes") for _, replication := range replications.Items { repl := replication k.WaitOn(t, k.Check(&repl, kmp.IsReady())) } return ctx }). Test("Verify Message In CouchDB Store", func(ctx f2.Context, t *testing.T) f2.Context { k := ktest.FromContextT(ctx, t) secret := corev1.Secret{} key := client.ObjectKey{Namespace: couchNamespace, Name: couchdb.StoreSecretName} err := k.Client.Get(ctx, key, &secret) assert.NilError(t, err, "fail to get couchdb store secret") servers := dsapi.CouchDBServerList{} assert.NilError(t, k.Client.List(ctx, &servers), "fail to list couchdb servers") for _, server := range servers.Items { pod := strings.Split(server.Spec.URI, ".")[0] portForward := portMapping[pod] addr := portForward.Retrieve(t) req, err := couchDBRequest(secret, fmt.Sprintf("http://%s", addr), fmt.Sprintf("db-%s", ctx.RunID), ctx.RunID) assert.NilError(t, err, "fail to create couchdb request") var resp *http.Response poll.WaitOn(t, func(_ poll.LogT) poll.Result { resp, err = http.DefaultClient.Do(req) if err == nil && resp.StatusCode == 200 { return poll.Success() } return poll.Continue("fail to get new db doc from couchdb Store: %s", errMessage(resp, req, err)) }, poll.WithDelay(k.Tick), poll.WithTimeout(k.Timeout*timeoutMultiplier)) } return ctx }). Test("Delete Created Database", func(ctx f2.Context, t *testing.T) f2.Context { result := pubSubClient.Topic(pubSubTopic).Publish(ctx, &pubsub.Message{ Attributes: map[string]string{ "tenant_id": bslInfo.OrganizationID, "db_name": fmt.Sprintf("db-%s", ctx.RunID), "entity_id": couchdb.AllDocs, "deleted": "true", "entity_type": "json", }, }) msgID, err := result.Get(ctx) assert.NilError(t, err, "fail to send delete message to pub/sub") t.Log("Sent pub/sub message Id:", msgID) return ctx }). Test("Verify DB Does Not Exists In The Cloud", func(ctx f2.Context, t *testing.T) f2.Context { k := ktest.FromContextT(ctx, t) secret := corev1.Secret{} key := client.ObjectKey{Namespace: "couchctl", Name: couchdb.StoreReplicationSecretName} err := k.Client.Get(ctx, key, &secret) assert.NilError(t, err, "fail to get couchdb master secret") req, err := couchDBRequest(secret, string(secret.Data["uri"]), fmt.Sprintf("db-%s", ctx.RunID), ctx.RunID) assert.NilError(t, err, "fail to create couchdb request") var resp *http.Response poll.WaitOn(t, func(_ poll.LogT) poll.Result { resp, err = http.DefaultClient.Do(req) if is404(resp) { return poll.Success() } return poll.Continue("fail to confirm doc deletion from couchdb master: %s", errMessage(resp, req, err)) }, poll.WithDelay(k.Tick), poll.WithTimeout(k.Timeout*timeoutMultiplier)) return ctx }). Test("Verify Replication Is Successful", func(ctx f2.Context, t *testing.T) f2.Context { k := ktest.FromContextT(ctx, t) replications := dsapi.CouchDBReplicationSetList{} err := k.Client.List(ctx, &replications, client.InNamespace(couchNamespace)) assert.NilError(t, err, "fail to list couchdb replications") assert.Check(t, cmp.Len(replications.Items, len(nodes.Items)), "number of couchdb replications not equal to number of nodes") for _, replication := range replications.Items { repl := replication k.WaitOn(t, k.Check(&repl, kmp.IsReady())) } return ctx }). Test("Verify DB Does Not Exists In The Store", func(ctx f2.Context, t *testing.T) f2.Context { k := ktest.FromContextT(ctx, t) secret := corev1.Secret{} key := client.ObjectKey{Namespace: couchNamespace, Name: couchdb.StoreSecretName} err := k.Client.Get(ctx, key, &secret) assert.NilError(t, err, "fail to get couchdb store secret") servers := dsapi.CouchDBServerList{} assert.NilError(t, k.Client.List(ctx, &servers), "fail to list couchdb servers") for _, server := range servers.Items { pod := strings.Split(server.Spec.URI, ".")[0] portForward := portMapping[pod] addr := portForward.Retrieve(t) req, err := couchDBRequest(secret, fmt.Sprintf("http://%s", addr), fmt.Sprintf("db-%s", ctx.RunID), ctx.RunID) assert.NilError(t, err, "fail to create couchdb request") var resp *http.Response poll.WaitOn(t, func(_ poll.LogT) poll.Result { resp, err = http.DefaultClient.Do(req) if is404(resp) { return poll.Success() } return poll.Continue("fail to confirm doc deletion in couchdb store: %s", errMessage(resp, req, err)) }, poll.WithDelay(k.Tick), poll.WithTimeout(k.Timeout*timeoutMultiplier)) } return ctx }). Feature() f.Test(t, feature) } func is404(resp *http.Response) bool { if resp != nil && resp.StatusCode == 404 { return true } return false }