Skip to content

Commit b6997ae

Browse files
pengzhoumlPeng Zhou
andauthored
MLE-4180 Add test automation for failover (#269)
* MLE-4180: Add Failover test automation * fix lint issue * fix test failure * add retries for put request * fix lint issue * MLE-15594: Fix test issues prompted by VSCode * close the tunnel --------- Co-authored-by: Peng Zhou <[email protected]>
1 parent 7f5dcf5 commit b6997ae

12 files changed

+266
-40
lines changed

test/e2e/admin_secrets_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func TestMlAdminSecrets(t *testing.T) {
1919
var helmChartPath string
2020
var initialChartVersion string
2121
upgradeHelm, _ := os.LookupEnv("upgradeTest")
22-
runUpgradeTest, err := strconv.ParseBool(upgradeHelm)
22+
runUpgradeTest, _ := strconv.ParseBool(upgradeHelm)
2323
if runUpgradeTest {
2424
initialChartVersion, _ = os.LookupEnv("initialChartVersion")
2525
t.Logf("====Setting initial Helm chart version: %s", initialChartVersion)
@@ -60,7 +60,7 @@ func TestMlAdminSecrets(t *testing.T) {
6060
defer k8s.DeleteNamespace(t, kubectlOptions, namespaceName)
6161

6262
// Path to the helm chart we will test
63-
helmChartPath, err = filepath.Abs("../../charts")
63+
helmChartPath, err := filepath.Abs("../../charts")
6464
if err != nil {
6565
t.Fatalf(err.Error())
6666
}

test/e2e/backup_restore_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ func TestMlDbBackupRestore(t *testing.T) {
144144
var podName string
145145
var initialChartVersion string
146146
upgradeHelm, _ := os.LookupEnv("upgradeTest")
147-
runUpgradeTest, err := strconv.ParseBool(upgradeHelm)
147+
runUpgradeTest, _ := strconv.ParseBool(upgradeHelm)
148148
if runUpgradeTest {
149149
initialChartVersion, _ = os.LookupEnv("initialChartVersion")
150150
t.Logf("====Setting initial Helm chart version: %s", initialChartVersion)

test/e2e/clustering_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func TestClusterJoin(t *testing.T) {
2828
password := "admin"
2929
var initialChartVersion string
3030
upgradeHelm, _ := os.LookupEnv("upgradeTest")
31-
runUpgradeTest, err := strconv.ParseBool(upgradeHelm)
31+
runUpgradeTest, _ := strconv.ParseBool(upgradeHelm)
3232
if runUpgradeTest {
3333
initialChartVersion, _ = os.LookupEnv("initialChartVersion")
3434
t.Logf("====Setting initial Helm chart version: %s", initialChartVersion)

test/e2e/env_param_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func TestEnableConvertersAndLicense(t *testing.T) {
3131
imageTag, tagPres := os.LookupEnv("dockerVersion")
3232
var initialChartVersion string
3333
upgradeHelm, _ := os.LookupEnv("upgradeTest")
34-
runUpgradeTest, err := strconv.ParseBool(upgradeHelm)
34+
runUpgradeTest, _ := strconv.ParseBool(upgradeHelm)
3535
if runUpgradeTest {
3636
initialChartVersion, _ = os.LookupEnv("initialChartVersion")
3737
t.Logf("====Setting initial Helm chart version: %s", initialChartVersion)

test/e2e/failover_test.go

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
package e2e
2+
3+
import (
4+
"crypto/tls"
5+
"fmt"
6+
"io"
7+
"os"
8+
"path/filepath"
9+
"strings"
10+
"testing"
11+
"time"
12+
13+
"github.com/gruntwork-io/terratest/modules/helm"
14+
"github.com/gruntwork-io/terratest/modules/k8s"
15+
"github.com/gruntwork-io/terratest/modules/random"
16+
"github.com/imroc/req/v3"
17+
"github.com/marklogic/marklogic-kubernetes/test/testUtil"
18+
"github.com/tidwall/gjson"
19+
// "github.com/tidwall/gjson"
20+
)
21+
22+
type Forest struct {
23+
ForestName string `json:"forest-name"`
24+
Host string `json:"host"`
25+
}
26+
27+
type ForestProperties struct {
28+
ForestReplica []ForestReplica `json:"forest-replica"`
29+
}
30+
31+
type ForestReplica struct {
32+
ReplicaName string `json:"replica-name"`
33+
Host string `json:"host"`
34+
}
35+
36+
func TestFailover(t *testing.T) {
37+
// Path to the helm chart we will test
38+
helmChartPath, e := filepath.Abs("../../charts")
39+
if e != nil {
40+
t.Fatalf(e.Error())
41+
}
42+
username := "admin"
43+
password := "admin"
44+
imageRepo, repoPres := os.LookupEnv("dockerRepository")
45+
imageTag, tagPres := os.LookupEnv("dockerVersion")
46+
if !repoPres {
47+
imageRepo = "progressofficial/marklogic-db"
48+
t.Logf("No imageRepo variable present, setting to default value: " + imageRepo)
49+
}
50+
51+
if !tagPres {
52+
imageTag = "latest-11"
53+
t.Logf("No imageTag variable present, setting to default value: " + imageTag)
54+
}
55+
56+
namespaceName := "ml-" + strings.ToLower(random.UniqueId())
57+
kubectlOptions := k8s.NewKubectlOptions("", "", namespaceName)
58+
options := &helm.Options{
59+
KubectlOptions: kubectlOptions,
60+
SetValues: map[string]string{
61+
"persistence.enabled": "true",
62+
"replicaCount": "3",
63+
"image.repository": imageRepo,
64+
"image.tag": imageTag,
65+
"auth.adminUsername": username,
66+
"auth.adminPassword": password,
67+
},
68+
}
69+
70+
t.Logf("====Creating namespace: " + namespaceName)
71+
k8s.CreateNamespace(t, kubectlOptions, namespaceName)
72+
73+
defer k8s.DeleteNamespace(t, kubectlOptions, namespaceName)
74+
75+
releaseName := "failover"
76+
hostName1 := fmt.Sprintf("%s-1.%s.%s.svc.cluster.local", releaseName, releaseName, namespaceName)
77+
forestName := "security1"
78+
79+
t.Logf("====Setting helm chart path to %s", helmChartPath)
80+
t.Logf("====Installing Helm Chart")
81+
testUtil.HelmInstall(t, options, releaseName, kubectlOptions, helmChartPath)
82+
podZeroName := releaseName + "-0"
83+
podOneName := releaseName + "-1"
84+
85+
// wait until the pod is in Ready status
86+
k8s.WaitUntilPodAvailable(t, kubectlOptions, podZeroName, 15, 20*time.Second)
87+
88+
tunnel := k8s.NewTunnel(
89+
kubectlOptions, k8s.ResourceTypePod, podZeroName, 8002, 8002)
90+
tunnel.ForwardPort(t)
91+
92+
client := req.C().DevMode()
93+
94+
// Create a new forest
95+
resp, err := client.R().
96+
SetDigestAuth(username, password).
97+
SetBody(&Forest{ForestName: forestName, Host: hostName1}).
98+
SetRetryCount(5).
99+
SetRetryFixedInterval(10 * time.Second).
100+
AddRetryCondition(func(resp *req.Response, err error) bool {
101+
if err != nil {
102+
t.Logf("error in AddRetryCondition: %s", err.Error())
103+
return true
104+
}
105+
if resp == nil {
106+
t.Logf("error getting response")
107+
return true
108+
}
109+
return resp.StatusCode != 201
110+
}).
111+
Post("http://localhost:8002/manage/v2/forests")
112+
113+
if err != nil {
114+
t.Errorf("Error creating forest %s", forestName)
115+
t.Fatalf(err.Error())
116+
}
117+
118+
if resp.StatusCode != 201 {
119+
t.Error("Response code is not 201 when creating forest. Actual response code", resp.Status)
120+
}
121+
122+
t.Logf("Forest %s created successfully", forestName)
123+
124+
// Set replica forest security1 for Security
125+
resp, err = client.R().
126+
SetDigestAuth(username, password).
127+
SetBody(&ForestProperties{ForestReplica: []ForestReplica{{ReplicaName: forestName, Host: hostName1}}}).
128+
SetRetryCount(5).
129+
SetRetryFixedInterval(10 * time.Second).
130+
AddRetryCondition(func(resp *req.Response, err error) bool {
131+
if err != nil {
132+
t.Logf("error in AddRetryCondition: %s", err.Error())
133+
return true
134+
}
135+
if resp == nil {
136+
t.Logf("error getting response")
137+
return true
138+
}
139+
return resp.StatusCode != 204
140+
}).
141+
Put("http://localhost:8002/manage/v2/forests/Security/properties")
142+
143+
if err != nil {
144+
t.Error("Error setting replica forest for Security")
145+
t.Fatalf(err.Error())
146+
}
147+
148+
if resp.StatusCode != 204 {
149+
t.Error("Response code is not 204 when updating forest replica. Actual response code", resp.Status)
150+
}
151+
152+
t.Log("Replica forest set for Security")
153+
154+
// Make sure the security1 forestg is in sync replicating state
155+
_, err = client.R().
156+
SetDigestAuth(username, password).
157+
SetRetryCount(5).
158+
SetRetryFixedInterval(10 * time.Second).
159+
AddRetryCondition(func(resp *req.Response, err error) bool {
160+
if err != nil {
161+
t.Logf("error in AddRetryCondition: %s", err.Error())
162+
return true
163+
}
164+
if resp == nil || resp.Body == nil {
165+
t.Logf("error in getting response body")
166+
return true
167+
}
168+
body, err := io.ReadAll(resp.Body)
169+
if body == nil || err != nil {
170+
t.Logf("error in read response body")
171+
return true
172+
}
173+
forestStatus := gjson.Get(string(body), `forest-status.status-properties.state.value`)
174+
t.Logf("Forest status waiting to be sync replicating, current status: %s", forestStatus.String())
175+
return forestStatus.String() != "sync replicating"
176+
}).
177+
Get("http://localhost:8002/manage/v2/forests/" + forestName + "?view=status&format=json")
178+
179+
if err != nil {
180+
t.Errorf("Error getting forest status for %s and waiting for sync replicating", forestName)
181+
t.Fatalf(err.Error())
182+
}
183+
184+
// delete the pod 0 to trigger Security forest failover to security1
185+
k8s.RunKubectl(t, kubectlOptions, "delete", "pod", podZeroName)
186+
187+
k8s.WaitUntilPodAvailable(t, kubectlOptions, podZeroName, 15, 20*time.Second)
188+
tunnel.Close()
189+
tunnel = k8s.NewTunnel(
190+
kubectlOptions, k8s.ResourceTypePod, podZeroName, 8002, 8002)
191+
defer tunnel.Close()
192+
tunnel.ForwardPort(t)
193+
194+
// Make sure the security1 forest1 is primary forest now and status is open
195+
_, err = client.R().
196+
SetDigestAuth(username, password).
197+
SetRetryCount(5).
198+
SetRetryFixedInterval(10 * time.Second).
199+
AddRetryCondition(func(resp *req.Response, err error) bool {
200+
if err != nil {
201+
t.Logf("error in AddRetryCondition: %s", err.Error())
202+
return true
203+
}
204+
if resp == nil || resp.Body == nil {
205+
t.Logf("error in getting response body")
206+
return true
207+
}
208+
body, err := io.ReadAll(resp.Body)
209+
if body == nil || err != nil {
210+
t.Logf("error in read response body: %s", err.Error())
211+
return true
212+
}
213+
forestStatus := gjson.Get(string(body), `forest-status.status-properties.state.value`)
214+
t.Logf("Forest status waiting to be open, current status: %s", forestStatus.String())
215+
return forestStatus.String() != "open"
216+
}).
217+
Get("http://localhost:8002/manage/v2/forests/" + forestName + "?view=status&format=json")
218+
219+
if err != nil {
220+
t.Error("Error getting forest status for security1 and waiting for open")
221+
t.Fatalf(err.Error())
222+
}
223+
224+
tlsConfig := tls.Config{}
225+
// restart all pods in the cluster and verify its ready and MarkLogic server is healthy
226+
testUtil.RestartPodAndVerify(t, true, []string{podZeroName, podOneName}, namespaceName, kubectlOptions, &tlsConfig)
227+
}

test/e2e/group_cfg_test.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,6 @@ func TestMultiGroupCfgChng(t *testing.T) {
125125
enodeGrpName := "enode"
126126
dnodeReleaseName := "dnode"
127127
enodeReleaseName := "enode"
128-
dnodePodName := dnodeReleaseName + "-0"
129-
enodePodName0 := enodeReleaseName + "-0"
130128

131129
// Path to the helm chart we will test
132130
helmChartPath, e := filepath.Abs("../../charts")
@@ -167,7 +165,7 @@ func TestMultiGroupCfgChng(t *testing.T) {
167165

168166
t.Logf("====Setting helm chart path to %s", helmChartPath)
169167
t.Logf("====Installing Helm Chart " + dnodeReleaseName)
170-
dnodePodName = testUtil.HelmInstall(t, options, dnodeReleaseName, kubectlOptions, helmChartPath)
168+
dnodePodName := testUtil.HelmInstall(t, options, dnodeReleaseName, kubectlOptions, helmChartPath)
171169

172170
// wait until the pod is in ready status
173171
k8s.WaitUntilPodAvailable(t, kubectlOptions, dnodePodName, 15, 20*time.Second)
@@ -224,7 +222,7 @@ func TestMultiGroupCfgChng(t *testing.T) {
224222
},
225223
}
226224
t.Logf("====Installing Helm Chart " + enodeReleaseName)
227-
enodePodName0 = testUtil.HelmInstall(t, enodeOptions, enodeReleaseName, kubectlOptions, helmChartPath)
225+
enodePodName0 := testUtil.HelmInstall(t, enodeOptions, enodeReleaseName, kubectlOptions, helmChartPath)
228226

229227
// wait until the first enode pod is in Ready status
230228
k8s.WaitUntilPodAvailable(t, kubectlOptions, enodePodName0, 15, 20*time.Second)

test/e2e/install_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func TestHelmInstall(t *testing.T) {
3131
imageRepo, repoPres := os.LookupEnv("dockerRepository")
3232
imageTag, tagPres := os.LookupEnv("dockerVersion")
3333
upgradeHelm, _ := os.LookupEnv("upgradeTest")
34-
runUpgradeTest, err := strconv.ParseBool(upgradeHelm)
34+
runUpgradeTest, _ := strconv.ParseBool(upgradeHelm)
3535
if runUpgradeTest {
3636
initialChartVersion, _ = os.LookupEnv("initialChartVersion")
3737
t.Logf("====Setting initial Helm chart version: %s", initialChartVersion)

test/e2e/ready_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ func TestMarklogicReady(t *testing.T) {
3030
imageRepo, repoPres := os.LookupEnv("dockerRepository")
3131
imageTag, tagPres := os.LookupEnv("dockerVersion")
3232
upgradeHelm, _ := os.LookupEnv("upgradeTest")
33-
runUpgradeTest, err := strconv.ParseBool(upgradeHelm)
33+
runUpgradeTest, _ := strconv.ParseBool(upgradeHelm)
3434
if runUpgradeTest {
3535
initialChartVersion, _ = os.LookupEnv("initialChartVersion")
3636
t.Logf("====Setting initial Helm chart version: %s", initialChartVersion)

test/e2e/scaling_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func TestHelmScaleUp(t *testing.T) {
2828
imageRepo, repoPres := os.LookupEnv("dockerRepository")
2929
imageTag, tagPres := os.LookupEnv("dockerVersion")
3030
upgradeHelm, _ := os.LookupEnv("upgradeTest")
31-
runUpgradeTest, err := strconv.ParseBool(upgradeHelm)
31+
runUpgradeTest, _ := strconv.ParseBool(upgradeHelm)
3232
if runUpgradeTest {
3333
initialChartVersion, _ = os.LookupEnv("initialChartVersion")
3434
t.Logf("====Setting initial Helm chart version: %s", initialChartVersion)

0 commit comments

Comments
 (0)