|
| 1 | +package v3 |
| 2 | + |
| 3 | +import ( |
| 4 | + "encoding/json" |
| 5 | + "fmt" |
| 6 | + "time" |
| 7 | + |
| 8 | + . "github.com/cloudfoundry/cf-acceptance-tests/cats_suite_helpers" |
| 9 | + "github.com/cloudfoundry/cf-acceptance-tests/helpers/app_helpers" |
| 10 | + "github.com/cloudfoundry/cf-acceptance-tests/helpers/assets" |
| 11 | + "github.com/cloudfoundry/cf-acceptance-tests/helpers/random_name" |
| 12 | + "github.com/cloudfoundry/cf-acceptance-tests/helpers/v3_helpers" |
| 13 | + "github.com/cloudfoundry/cf-test-helpers/v2/cf" |
| 14 | + . "github.com/onsi/ginkgo/v2" |
| 15 | + . "github.com/onsi/gomega" |
| 16 | + . "github.com/onsi/gomega/gbytes" |
| 17 | + . "github.com/onsi/gomega/gexec" |
| 18 | +) |
| 19 | + |
| 20 | +type ProcessInstance struct { |
| 21 | + Index int `json:"index"` |
| 22 | + State string `json:"state"` |
| 23 | + Since int `json:"since"` |
| 24 | +} |
| 25 | + |
| 26 | +type ProcessInstancesResource struct { |
| 27 | + ProcessInstances []ProcessInstance `json:"resources"` |
| 28 | +} |
| 29 | + |
| 30 | +type ProcessResource struct { |
| 31 | + ProcessInstances []ProcessInstance `json:"process_instances"` |
| 32 | +} |
| 33 | + |
| 34 | +type ProcessesResource struct { |
| 35 | + Processes []ProcessResource `json:"resources"` |
| 36 | +} |
| 37 | + |
| 38 | +var _ = V3Describe("process instances", func() { |
| 39 | + var ( |
| 40 | + appName string |
| 41 | + webProcess v3_helpers.Process |
| 42 | + ) |
| 43 | + |
| 44 | + BeforeEach(func() { |
| 45 | + appName = random_name.CATSRandomName("APP") |
| 46 | + |
| 47 | + By("pushing the app with three instances") |
| 48 | + Expect(cf.Cf("push", appName, "-i", "3", "-b", Config.GetRubyBuildpackName(), "-p", assets.NewAssets().DoraZip).Wait(Config.CfPushTimeoutDuration())).To(Exit(0)) |
| 49 | + |
| 50 | + By("waiting until all instances are running") |
| 51 | + Eventually(func(g Gomega) { |
| 52 | + session := cf.Cf("app", appName).Wait() |
| 53 | + g.Expect(session).Should(Say(`instances:\s+3/3`)) |
| 54 | + }).Should(Succeed()) |
| 55 | + |
| 56 | + appGuid := app_helpers.GetAppGuid(appName) |
| 57 | + processes := v3_helpers.GetProcesses(appGuid, appName) |
| 58 | + webProcess = v3_helpers.GetProcessByType(processes, "web") |
| 59 | + }) |
| 60 | + |
| 61 | + AfterEach(func() { |
| 62 | + app_helpers.AppReport(appName) |
| 63 | + Expect(cf.Cf("delete", appName, "-f").Wait(Config.DefaultTimeoutDuration())).To(Exit(0)) |
| 64 | + }) |
| 65 | + |
| 66 | + Context("via different v3 API endpoints", func() { |
| 67 | + It("returns an array of process instances", func() { |
| 68 | + By("/v3/processes/:guid/process_instances") |
| 69 | + { |
| 70 | + resource := ProcessInstancesResource{} |
| 71 | + getResource(fmt.Sprintf("v3/processes/%s/process_instances", webProcess.Guid), &resource) |
| 72 | + Expect(len(resource.ProcessInstances)).To(Equal(3)) |
| 73 | + |
| 74 | + for index, instance := range resource.ProcessInstances { |
| 75 | + checkProcessInstance(instance, index, "RUNNING") |
| 76 | + } |
| 77 | + } |
| 78 | + |
| 79 | + By("/v3/processes/:guid?embed=process_instances") |
| 80 | + { |
| 81 | + resource := ProcessResource{} |
| 82 | + getResource(fmt.Sprintf("v3/processes/%s?embed=process_instances", webProcess.Guid), &resource) |
| 83 | + Expect(len(resource.ProcessInstances)).To(Equal(3)) |
| 84 | + |
| 85 | + for index, instance := range resource.ProcessInstances { |
| 86 | + checkProcessInstance(instance, index, "RUNNING") |
| 87 | + } |
| 88 | + } |
| 89 | + |
| 90 | + By("/v3/processes?guids=:guid&embed=process_instances") |
| 91 | + { |
| 92 | + resource := ProcessesResource{} |
| 93 | + getResource(fmt.Sprintf("v3/processes?guids=%s&embed=process_instances", webProcess.Guid), &resource) |
| 94 | + Expect(len(resource.Processes)).To(Equal(1)) |
| 95 | + Expect(len(resource.Processes[0].ProcessInstances)).To(Equal(3)) |
| 96 | + |
| 97 | + for index, instance := range resource.Processes[0].ProcessInstances { |
| 98 | + checkProcessInstance(instance, index, "RUNNING") |
| 99 | + } |
| 100 | + } |
| 101 | + }) |
| 102 | + }) |
| 103 | + |
| 104 | + Context("when stopping the app", func() { |
| 105 | + It("switches the instances' state from RUNNING to DOWN", func() { |
| 106 | + resource := ProcessInstancesResource{} |
| 107 | + getResource(fmt.Sprintf("v3/processes/%s/process_instances", webProcess.Guid), &resource) |
| 108 | + Expect(len(resource.ProcessInstances)).To(Equal(3)) |
| 109 | + |
| 110 | + for index, instance := range resource.ProcessInstances { |
| 111 | + checkProcessInstance(instance, index, "RUNNING") |
| 112 | + } |
| 113 | + |
| 114 | + By("stopping the app") |
| 115 | + Expect(cf.Cf("stop", appName).Wait(Config.DefaultTimeoutDuration())).To(Exit(0)) |
| 116 | + |
| 117 | + By("waiting until all instances are stopped") |
| 118 | + Eventually(func() []string { |
| 119 | + getResource(fmt.Sprintf("v3/processes/%s/process_instances", webProcess.Guid), &resource) |
| 120 | + states := []string{} |
| 121 | + for _, instance := range resource.ProcessInstances { |
| 122 | + states = append(states, instance.State) |
| 123 | + } |
| 124 | + return states |
| 125 | + }, V3_PROCESS_TIMEOUT, 1*time.Second).Should(Equal([]string{"DOWN", "DOWN", "DOWN"})) |
| 126 | + Expect(len(resource.ProcessInstances)).To(Equal(3)) |
| 127 | + |
| 128 | + for index, instance := range resource.ProcessInstances { |
| 129 | + checkProcessInstance(instance, index, "DOWN") |
| 130 | + } |
| 131 | + }) |
| 132 | + }) |
| 133 | +}) |
| 134 | + |
| 135 | +func getResource(url string, resource any) { |
| 136 | + json.Unmarshal(cf.Cf("curl", url).Wait().Out.Contents(), &resource) |
| 137 | +} |
| 138 | + |
| 139 | +func checkProcessInstance(instance ProcessInstance, index int, state string) { |
| 140 | + Expect(instance.Index).To(Equal(index)) |
| 141 | + Expect(instance.State).To(Equal(state)) |
| 142 | + Expect(instance.Since).To(BeNumerically(">", 0)) |
| 143 | +} |
0 commit comments