@@ -3,6 +3,7 @@ package tasks
33import (
44 "omakase/subprocess"
55 "os"
6+ "strings"
67 "testing"
78)
89
@@ -25,6 +26,31 @@ func skipIfNoDokkuT(t *testing.T) {
2526 }
2627}
2728
29+ func dokkuPluginInstalled (plugin string ) bool {
30+ result , err := subprocess .CallExecCommand (subprocess.ExecCommandInput {
31+ Command : "dokku" ,
32+ Args : []string {"plugin:list" },
33+ })
34+ if err != nil {
35+ return false
36+ }
37+
38+ for _ , line := range strings .Split (result .StdoutContents (), "\n " ) {
39+ fields := strings .Fields (line )
40+ if len (fields ) > 0 && fields [0 ] == plugin {
41+ return true
42+ }
43+ }
44+ return false
45+ }
46+
47+ func skipIfPluginMissingT (t * testing.T , plugin string ) {
48+ t .Helper ()
49+ if ! dokkuPluginInstalled (plugin ) {
50+ t .Skipf ("skipping integration test: dokku plugin %q not installed" , plugin )
51+ }
52+ }
53+
2854func TestIntegrationAppCreateAndDestroy (t * testing.T ) {
2955 skipIfNoDokkuT (t )
3056
@@ -934,3 +960,64 @@ func TestIntegrationMultiTaskWorkflow(t *testing.T) {
934960 }
935961 }
936962}
963+
964+ func TestIntegrationServiceCreateAndDestroy (t * testing.T ) {
965+ skipIfNoDokkuT (t )
966+ skipIfPluginMissingT (t , "redis" )
967+
968+ serviceName := "omakase-test-service"
969+ serviceType := "redis"
970+
971+ // ensure clean state
972+ destroyService (serviceType , serviceName )
973+
974+ // create the service
975+ task := ServiceCreateTask {Service : serviceType , Name : serviceName , State : StatePresent }
976+ result := task .Execute ()
977+ if result .Error != nil {
978+ t .Fatalf ("failed to create service: %v" , result .Error )
979+ }
980+ if result .State != StatePresent {
981+ t .Errorf ("expected state 'present', got '%s'" , result .State )
982+ }
983+ if ! result .Changed {
984+ t .Error ("expected changed=true for new service creation" )
985+ }
986+
987+ // creating again should be idempotent
988+ result = task .Execute ()
989+ if result .Error != nil {
990+ t .Fatalf ("idempotent create failed: %v" , result .Error )
991+ }
992+ if result .Changed {
993+ t .Error ("expected changed=false for existing service" )
994+ }
995+ if result .State != StatePresent {
996+ t .Errorf ("expected state 'present', got '%s'" , result .State )
997+ }
998+
999+ // destroy the service
1000+ destroyTask := ServiceCreateTask {Service : serviceType , Name : serviceName , State : StateAbsent }
1001+ result = destroyTask .Execute ()
1002+ if result .Error != nil {
1003+ t .Fatalf ("failed to destroy service: %v" , result .Error )
1004+ }
1005+ if result .State != StateAbsent {
1006+ t .Errorf ("expected state 'absent', got '%s'" , result .State )
1007+ }
1008+ if ! result .Changed {
1009+ t .Error ("expected changed=true for service destruction" )
1010+ }
1011+
1012+ // destroying again should be idempotent
1013+ result = destroyTask .Execute ()
1014+ if result .Error != nil {
1015+ t .Fatalf ("idempotent destroy failed: %v" , result .Error )
1016+ }
1017+ if result .Changed {
1018+ t .Error ("expected changed=false for nonexistent service" )
1019+ }
1020+ if result .State != StateAbsent {
1021+ t .Errorf ("expected state 'absent', got '%s'" , result .State )
1022+ }
1023+ }
0 commit comments