@@ -41,8 +41,8 @@ import (
41
41
// +kubebuilder:scaffold:imports
42
42
)
43
43
44
- func rayServiceTemplate ( name string , namespace string , serveAppName string ) * rayv1. RayService {
45
- serveConfigV2 := fmt .Sprintf (`
44
+ func serveConfigV2Template ( serveAppName string ) string {
45
+ return fmt .Sprintf (`
46
46
applications:
47
47
- name: %s
48
48
import_path: fruit.deployment_graph
@@ -68,7 +68,10 @@ func rayServiceTemplate(name string, namespace string, serveAppName string) *ray
68
68
price: 1
69
69
ray_actor_options:
70
70
num_cpus: 0.1` , serveAppName )
71
+ }
71
72
73
+ func rayServiceTemplate (name string , namespace string , serveAppName string ) * rayv1.RayService {
74
+ serveConfigV2 := serveConfigV2Template (serveAppName )
72
75
return & rayv1.RayService {
73
76
ObjectMeta : metav1.ObjectMeta {
74
77
Name : name ,
@@ -115,15 +118,130 @@ func rayServiceTemplate(name string, namespace string, serveAppName string) *ray
115
118
}
116
119
}
117
120
118
- var _ = Context ("Inside the default namespace" , func () {
119
- ctx := context .TODO ()
120
- var workerPods corev1.PodList
121
+ func endpointsTemplate (name string , namespace string ) * corev1.Endpoints {
122
+ return & corev1.Endpoints {
123
+ ObjectMeta : metav1.ObjectMeta {
124
+ Name : name ,
125
+ Namespace : namespace ,
126
+ },
127
+ Subsets : []corev1.EndpointSubset {
128
+ {
129
+ Addresses : []corev1.EndpointAddress {
130
+ {
131
+ IP : "10.9.8.7" ,
132
+ },
133
+ },
134
+ },
135
+ },
136
+ }
137
+ }
138
+
139
+ var _ = Context ("RayService env tests" , func () {
140
+ Describe ("RayService happy path" , Ordered , func () {
141
+ // This test case simulates the most common scenario in the RayService code path:
142
+ // (1) Create a RayService custom resource
143
+ // (2) The RayService controller creates a pending RayCluster
144
+ // (3) The serve application becomes ready on the pending RayCluster
145
+ // (4) The Kubernetes head and serve services are created
146
+ // (5) The pending RayCluster transitions to become the active RayCluster
147
+ ctx := context .Background ()
148
+ namespace := "default"
149
+ serveAppName := "app1"
150
+ rayService := rayServiceTemplate ("test-happy-path" , namespace , serveAppName )
151
+ rayCluster := & rayv1.RayCluster {}
152
+
153
+ It ("Create a RayService custom resource" , func () {
154
+ err := k8sClient .Create (ctx , rayService )
155
+ Expect (err ).NotTo (HaveOccurred (), "failed to create RayService resource" )
156
+ Eventually (
157
+ getResourceFunc (ctx , client.ObjectKey {Name : rayService .Name , Namespace : namespace }, rayService ),
158
+ time .Second * 3 , time .Millisecond * 500 ).Should (BeNil (), "RayService: %v" , rayService .Name )
159
+ })
160
+
161
+ It ("Conditions should be initialized correctly" , func () {
162
+ Eventually (
163
+ func () bool {
164
+ return meta .IsStatusConditionTrue (rayService .Status .Conditions , string (rayv1 .UpgradeInProgress ))
165
+ },
166
+ time .Second * 3 , time .Millisecond * 500 ).Should (BeFalse (), "UpgradeInProgress condition: %v" , rayService .Status .Conditions )
167
+ Eventually (
168
+ func () bool {
169
+ return meta .IsStatusConditionTrue (rayService .Status .Conditions , string (rayv1 .RayServiceReady ))
170
+ },
171
+ time .Second * 3 , time .Millisecond * 500 ).Should (BeFalse (), "RayServiceReady condition: %v" , rayService .Status .Conditions )
172
+ })
173
+
174
+ It ("Should create a pending RayCluster" , func () {
175
+ Eventually (
176
+ getPreparingRayClusterNameFunc (ctx , rayService ),
177
+ time .Second * 15 , time .Millisecond * 500 ).Should (Not (BeEmpty ()), "Pending RayCluster name: %v" , rayService .Status .PendingServiceStatus .RayClusterName )
178
+ })
179
+
180
+ It ("Promote the pending RayCluster to the active RayCluster" , func () {
181
+ // Update the status of the head Pod to Running. Note that the default fake dashboard client
182
+ // will return a healthy serve application status.
183
+ pendingRayClusterName := rayService .Status .PendingServiceStatus .RayClusterName
184
+ updateHeadPodToRunningAndReady (ctx , pendingRayClusterName , namespace )
185
+
186
+ // Make sure the pending RayCluster becomes the active RayCluster.
187
+ Eventually (
188
+ getRayClusterNameFunc (ctx , rayService ),
189
+ time .Second * 15 , time .Millisecond * 500 ).Should (Equal (pendingRayClusterName ), "Active RayCluster name: %v" , rayService .Status .ActiveServiceStatus .RayClusterName )
190
+
191
+ // Initialize RayCluster for the following tests.
192
+ Eventually (
193
+ getResourceFunc (ctx , client.ObjectKey {Name : rayService .Status .ActiveServiceStatus .RayClusterName , Namespace : namespace }, rayCluster ),
194
+ time .Second * 3 , time .Millisecond * 500 ).Should (BeNil (), "RayCluster: %v" , rayCluster .Name )
195
+ })
196
+
197
+ It ("Check the serve application status in the RayService status" , func () {
198
+ // Check the serve application status in the RayService status.
199
+ // The serve application should be healthy.
200
+ Eventually (
201
+ checkServiceHealth (ctx , rayService ),
202
+ time .Second * 3 , time .Millisecond * 500 ).Should (BeTrue (), "RayService status: %v" , rayService .Status )
203
+ })
204
+
205
+ It ("Should create a new head service resource" , func () {
206
+ svc := & corev1.Service {}
207
+ headSvcName , err := utils .GenerateHeadServiceName (utils .RayServiceCRD , rayService .Spec .RayClusterSpec , rayService .Name )
208
+ Expect (err ).ToNot (HaveOccurred ())
209
+ Eventually (
210
+ getResourceFunc (ctx , client.ObjectKey {Name : headSvcName , Namespace : namespace }, svc ),
211
+ time .Second * 3 , time .Millisecond * 500 ).Should (BeNil (), "Head service: %v" , svc )
212
+ // TODO: Verify the head service by checking labels and annotations.
213
+ })
214
+
215
+ It ("Should create a new serve service resource" , func () {
216
+ svc := & corev1.Service {}
217
+ Eventually (
218
+ getResourceFunc (ctx , client.ObjectKey {Name : utils .GenerateServeServiceName (rayService .Name ), Namespace : namespace }, svc ),
219
+ time .Second * 3 , time .Millisecond * 500 ).Should (BeNil (), "Serve service: %v" , svc )
220
+ // TODO: Verify the serve service by checking labels and annotations.
221
+ })
121
222
122
- serveAppName := "app1"
123
- rayService := rayServiceTemplate ("rayservice-sample" , "default" , serveAppName )
124
- myRayCluster := & rayv1.RayCluster {}
223
+ It ("The RayServiceReady condition should be true when the number of endpoints is greater than 0" , func () {
224
+ endpoints := endpointsTemplate (utils .GenerateServeServiceName (rayService .Name ), namespace )
225
+ err := k8sClient .Create (ctx , endpoints )
226
+ Expect (err ).NotTo (HaveOccurred (), "failed to create Endpoints resource" )
227
+ Eventually (func () int32 {
228
+ if err := k8sClient .Get (ctx , client.ObjectKey {Name : rayService .Name , Namespace : namespace }, rayService ); err != nil {
229
+ return 0
230
+ }
231
+ return rayService .Status .NumServeEndpoints
232
+ }, time .Second * 3 , time .Millisecond * 500 ).Should (BeNumerically (">" , 0 ), "RayService status: %v" , rayService .Status )
233
+ Expect (meta .IsStatusConditionTrue (rayService .Status .Conditions , string (rayv1 .RayServiceReady ))).Should (BeTrue ())
234
+ })
235
+ })
125
236
126
237
Describe ("When creating a rayservice" , Ordered , func () {
238
+ ctx := context .TODO ()
239
+ var workerPods corev1.PodList
240
+
241
+ serveAppName := "app1"
242
+ rayService := rayServiceTemplate ("rayservice-sample" , "default" , serveAppName )
243
+ myRayCluster := & rayv1.RayCluster {}
244
+
127
245
It ("should create a rayservice object" , func () {
128
246
err := k8sClient .Create (ctx , rayService )
129
247
Expect (err ).NotTo (HaveOccurred (), "failed to create test RayService resource" )
@@ -135,15 +253,6 @@ var _ = Context("Inside the default namespace", func() {
135
253
time .Second * 3 , time .Millisecond * 500 ).Should (BeNil (), "My myRayService = %v" , rayService .Name )
136
254
})
137
255
138
- It ("should initialize conditions correctly" , func () {
139
- Eventually (func () bool {
140
- if err := k8sClient .Get (ctx , client.ObjectKey {Name : rayService .Name , Namespace : "default" }, rayService ); err != nil {
141
- return false
142
- }
143
- return meta .IsStatusConditionFalse (rayService .Status .Conditions , string (rayv1 .RayServiceReady )) && meta .IsStatusConditionFalse (rayService .Status .Conditions , string (rayv1 .UpgradeInProgress ))
144
- }, time .Second * 3 , time .Millisecond * 500 ).Should (BeTrue (), "My myRayService conditions = %v" , rayService .Status .Conditions )
145
- })
146
-
147
256
It ("should create a raycluster object" , func () {
148
257
Eventually (
149
258
getPreparingRayClusterNameFunc (ctx , rayService ),
@@ -203,34 +312,6 @@ var _ = Context("Inside the default namespace", func() {
203
312
Expect (svc .Spec .Selector [utils .RayClusterLabelKey ]).Should (Equal (myRayCluster .Name ))
204
313
})
205
314
206
- It ("should have true Ready condition when number of endpoints is greater than 0" , func () {
207
- endpoints := & corev1.Endpoints {
208
- ObjectMeta : metav1.ObjectMeta {
209
- Name : utils .GenerateServeServiceName (rayService .Name ),
210
- Namespace : "default" ,
211
- },
212
- Subsets : []corev1.EndpointSubset {
213
- {
214
- Addresses : []corev1.EndpointAddress {
215
- {
216
- IP : "10.9.8.7" ,
217
- },
218
- },
219
- },
220
- },
221
- }
222
- err := k8sClient .Create (ctx , endpoints )
223
- Expect (err ).NotTo (HaveOccurred (), "failed to create test Endpoints resource" )
224
-
225
- Eventually (func () int32 {
226
- if err := k8sClient .Get (ctx , client.ObjectKey {Name : rayService .Name , Namespace : "default" }, rayService ); err != nil {
227
- return 0
228
- }
229
- return rayService .Status .NumServeEndpoints
230
- }, time .Second * 3 , time .Millisecond * 500 ).Should (BeNumerically (">" , 0 ), "My myRayService status = %v" , rayService .Status )
231
- Expect (meta .IsStatusConditionTrue (rayService .Status .Conditions , string (rayv1 .RayServiceReady ))).Should (BeTrue ())
232
- })
233
-
234
315
It ("should update a rayservice object and switch to new Ray Cluster" , func () {
235
316
err := retry .RetryOnConflict (retry .DefaultRetry , func () error {
236
317
Eventually (
0 commit comments