@@ -190,6 +190,9 @@ func TestTemplateStorageUpdateReturnsDesiredObjectForLegacyRunningField(t *testi
190190 if ! ok {
191191 t .Fatalf ("expected *CoderTemplate from get, got %T" , currentObj )
192192 }
193+ if currentTemplate .ResourceVersion == "" {
194+ t .Fatal ("expected current template resourceVersion to be populated" )
195+ }
193196
194197 desiredTemplate := currentTemplate .DeepCopy ()
195198 desiredTemplate .Spec .Running = ! currentTemplate .Spec .Running
@@ -358,6 +361,89 @@ func TestTemplateStorageUpdateRejectsNonRunningSpecChanges(t *testing.T) {
358361 }
359362}
360363
364+ func TestTemplateStorageUpdateRejectsMissingResourceVersion (t * testing.T ) {
365+ t .Parallel ()
366+
367+ server , _ := newMockCoderServer (t )
368+ defer server .Close ()
369+
370+ templateStorage := NewTemplateStorage (newTestClientProvider (t , server .URL ))
371+ ctx := namespacedContext ("control-plane" )
372+
373+ currentObj , err := templateStorage .Get (ctx , "acme.starter-template" , nil )
374+ if err != nil {
375+ t .Fatalf ("expected template get to succeed: %v" , err )
376+ }
377+
378+ currentTemplate , ok := currentObj .(* aggregationv1alpha1.CoderTemplate )
379+ if ! ok {
380+ t .Fatalf ("expected *CoderTemplate from get, got %T" , currentObj )
381+ }
382+ if currentTemplate .ResourceVersion == "" {
383+ t .Fatal ("expected current template resourceVersion to be populated" )
384+ }
385+
386+ desiredTemplate := currentTemplate .DeepCopy ()
387+ desiredTemplate .Spec .Running = ! currentTemplate .Spec .Running
388+ desiredTemplate .ResourceVersion = ""
389+
390+ _ , _ , err = templateStorage .Update (
391+ ctx ,
392+ desiredTemplate .Name ,
393+ testUpdatedObjectInfo {obj : desiredTemplate },
394+ nil ,
395+ rest .ValidateAllObjectUpdateFunc ,
396+ false ,
397+ nil ,
398+ )
399+ if ! apierrors .IsBadRequest (err ) {
400+ t .Fatalf ("expected BadRequest for missing resourceVersion, got %v" , err )
401+ }
402+ if err == nil || ! strings .Contains (err .Error (), "metadata.resourceVersion is required for update" ) {
403+ t .Fatalf ("expected missing resourceVersion error message, got %v" , err )
404+ }
405+ }
406+
407+ func TestTemplateStorageUpdateRejectsStaleResourceVersion (t * testing.T ) {
408+ t .Parallel ()
409+
410+ server , _ := newMockCoderServer (t )
411+ defer server .Close ()
412+
413+ templateStorage := NewTemplateStorage (newTestClientProvider (t , server .URL ))
414+ ctx := namespacedContext ("control-plane" )
415+
416+ currentObj , err := templateStorage .Get (ctx , "acme.starter-template" , nil )
417+ if err != nil {
418+ t .Fatalf ("expected template get to succeed: %v" , err )
419+ }
420+
421+ currentTemplate , ok := currentObj .(* aggregationv1alpha1.CoderTemplate )
422+ if ! ok {
423+ t .Fatalf ("expected *CoderTemplate from get, got %T" , currentObj )
424+ }
425+
426+ desiredTemplate := currentTemplate .DeepCopy ()
427+ desiredTemplate .Spec .Running = ! currentTemplate .Spec .Running
428+ desiredTemplate .ResourceVersion = currentTemplate .ResourceVersion + "-stale"
429+
430+ _ , _ , err = templateStorage .Update (
431+ ctx ,
432+ desiredTemplate .Name ,
433+ testUpdatedObjectInfo {obj : desiredTemplate },
434+ nil ,
435+ rest .ValidateAllObjectUpdateFunc ,
436+ false ,
437+ nil ,
438+ )
439+ if ! apierrors .IsConflict (err ) {
440+ t .Fatalf ("expected Conflict for stale resourceVersion, got %v" , err )
441+ }
442+ if err == nil || ! strings .Contains (err .Error (), "resource version mismatch" ) {
443+ t .Fatalf ("expected stale resourceVersion error message, got %v" , err )
444+ }
445+ }
446+
361447func TestWorkspaceStorageCRUDWithCoderSDK (t * testing.T ) {
362448 t .Parallel ()
363449
0 commit comments