github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/builtin/provisioners/remote-exec/resource_provisioner_test.go (about) 1 package remoteexec 2 3 import ( 4 "bytes" 5 "context" 6 "io" 7 "testing" 8 "time" 9 10 "strings" 11 12 "github.com/hashicorp/terraform/communicator" 13 "github.com/hashicorp/terraform/communicator/remote" 14 "github.com/hashicorp/terraform/helper/schema" 15 "github.com/hashicorp/terraform/terraform" 16 ) 17 18 func TestResourceProvisioner_impl(t *testing.T) { 19 var _ terraform.ResourceProvisioner = Provisioner() 20 } 21 22 func TestProvisioner(t *testing.T) { 23 if err := Provisioner().(*schema.Provisioner).InternalValidate(); err != nil { 24 t.Fatalf("err: %s", err) 25 } 26 } 27 28 func TestResourceProvider_Validate_good(t *testing.T) { 29 c := testConfig(t, map[string]interface{}{ 30 "inline": "echo foo", 31 }) 32 33 warn, errs := Provisioner().Validate(c) 34 if len(warn) > 0 { 35 t.Fatalf("Warnings: %v", warn) 36 } 37 if len(errs) > 0 { 38 t.Fatalf("Errors: %v", errs) 39 } 40 } 41 42 func TestResourceProvider_Validate_bad(t *testing.T) { 43 c := testConfig(t, map[string]interface{}{ 44 "invalid": "nope", 45 }) 46 47 warn, errs := Provisioner().Validate(c) 48 if len(warn) > 0 { 49 t.Fatalf("Warnings: %v", warn) 50 } 51 if len(errs) == 0 { 52 t.Fatalf("Should have errors") 53 } 54 } 55 56 var expectedScriptOut = `cd /tmp 57 wget http://foobar 58 exit 0 59 ` 60 61 func TestResourceProvider_generateScript(t *testing.T) { 62 conf := map[string]interface{}{ 63 "inline": []interface{}{ 64 "cd /tmp", 65 "wget http://foobar", 66 "exit 0", 67 }, 68 } 69 70 out, err := generateScripts( 71 schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, conf), 72 ) 73 if err != nil { 74 t.Fatalf("err: %v", err) 75 } 76 77 if len(out) != 1 { 78 t.Fatal("expected 1 out") 79 } 80 81 if out[0] != expectedScriptOut { 82 t.Fatalf("bad: %v", out) 83 } 84 } 85 86 func TestResourceProvider_generateScriptEmptyInline(t *testing.T) { 87 p := Provisioner().(*schema.Provisioner) 88 conf := map[string]interface{}{ 89 "inline": []interface{}{""}, 90 } 91 92 _, err := generateScripts(schema.TestResourceDataRaw( 93 t, p.Schema, conf)) 94 if err == nil { 95 t.Fatal("expected error, got none") 96 } 97 98 if !strings.Contains(err.Error(), "Error parsing") { 99 t.Fatalf("expected parsing error, got: %s", err) 100 } 101 } 102 103 func TestResourceProvider_CollectScripts_inline(t *testing.T) { 104 conf := map[string]interface{}{ 105 "inline": []interface{}{ 106 "cd /tmp", 107 "wget http://foobar", 108 "exit 0", 109 }, 110 } 111 112 scripts, err := collectScripts( 113 schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, conf), 114 ) 115 if err != nil { 116 t.Fatalf("err: %v", err) 117 } 118 119 if len(scripts) != 1 { 120 t.Fatalf("bad: %v", scripts) 121 } 122 123 var out bytes.Buffer 124 _, err = io.Copy(&out, scripts[0]) 125 if err != nil { 126 t.Fatalf("err: %v", err) 127 } 128 129 if out.String() != expectedScriptOut { 130 t.Fatalf("bad: %v", out.String()) 131 } 132 } 133 134 func TestResourceProvider_CollectScripts_script(t *testing.T) { 135 conf := map[string]interface{}{ 136 "script": "testdata/script1.sh", 137 } 138 139 scripts, err := collectScripts( 140 schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, conf), 141 ) 142 if err != nil { 143 t.Fatalf("err: %v", err) 144 } 145 146 if len(scripts) != 1 { 147 t.Fatalf("bad: %v", scripts) 148 } 149 150 var out bytes.Buffer 151 _, err = io.Copy(&out, scripts[0]) 152 if err != nil { 153 t.Fatalf("err: %v", err) 154 } 155 156 if out.String() != expectedScriptOut { 157 t.Fatalf("bad: %v", out.String()) 158 } 159 } 160 161 func TestResourceProvider_CollectScripts_scripts(t *testing.T) { 162 conf := map[string]interface{}{ 163 "scripts": []interface{}{ 164 "testdata/script1.sh", 165 "testdata/script1.sh", 166 "testdata/script1.sh", 167 }, 168 } 169 170 scripts, err := collectScripts( 171 schema.TestResourceDataRaw(t, Provisioner().(*schema.Provisioner).Schema, conf), 172 ) 173 if err != nil { 174 t.Fatalf("err: %v", err) 175 } 176 177 if len(scripts) != 3 { 178 t.Fatalf("bad: %v", scripts) 179 } 180 181 for idx := range scripts { 182 var out bytes.Buffer 183 _, err = io.Copy(&out, scripts[idx]) 184 if err != nil { 185 t.Fatalf("err: %v", err) 186 } 187 188 if out.String() != expectedScriptOut { 189 t.Fatalf("bad: %v", out.String()) 190 } 191 } 192 } 193 194 func TestResourceProvider_CollectScripts_scriptsEmpty(t *testing.T) { 195 p := Provisioner().(*schema.Provisioner) 196 conf := map[string]interface{}{ 197 "scripts": []interface{}{""}, 198 } 199 200 _, err := collectScripts(schema.TestResourceDataRaw( 201 t, p.Schema, conf)) 202 203 if err == nil { 204 t.Fatal("expected error") 205 } 206 207 if !strings.Contains(err.Error(), "Error parsing") { 208 t.Fatalf("Expected parsing error, got: %s", err) 209 } 210 } 211 212 func TestProvisionerTimeout(t *testing.T) { 213 o := new(terraform.MockUIOutput) 214 c := new(communicator.MockCommunicator) 215 216 disconnected := make(chan struct{}) 217 c.DisconnectFunc = func() error { 218 close(disconnected) 219 return nil 220 } 221 222 completed := make(chan struct{}) 223 c.CommandFunc = func(cmd *remote.Cmd) error { 224 defer close(completed) 225 cmd.Init() 226 time.Sleep(2 * time.Second) 227 cmd.SetExitStatus(0, nil) 228 return nil 229 } 230 c.ConnTimeout = time.Second 231 c.UploadScripts = map[string]string{"hello": "echo hello"} 232 c.RemoteScriptPath = "hello" 233 234 p := Provisioner().(*schema.Provisioner) 235 conf := map[string]interface{}{ 236 "inline": []interface{}{"echo hello"}, 237 } 238 239 scripts, err := collectScripts(schema.TestResourceDataRaw( 240 t, p.Schema, conf)) 241 if err != nil { 242 t.Fatal(err) 243 } 244 245 ctx := context.Background() 246 247 done := make(chan struct{}) 248 249 go func() { 250 defer close(done) 251 if err := runScripts(ctx, o, c, scripts); err != nil { 252 t.Fatal(err) 253 } 254 }() 255 256 select { 257 case <-disconnected: 258 t.Fatal("communicator disconnected before command completed") 259 case <-completed: 260 } 261 262 <-done 263 } 264 265 func testConfig(t *testing.T, c map[string]interface{}) *terraform.ResourceConfig { 266 return terraform.NewResourceConfigRaw(c) 267 }