2023-03-02 15:37:05 -05:00
// Copyright (c) HashiCorp, Inc.
2023-08-10 15:53:29 -07:00
// SPDX-License-Identifier: BUSL-1.1
2023-03-02 15:37:05 -05:00
2015-06-14 11:23:29 -07:00
package shell
import (
"bytes"
2019-03-19 18:11:19 +01:00
"context"
2015-06-14 11:23:29 -07:00
"log"
"os"
"strings"
"testing"
2017-08-07 13:20:01 -04:00
2020-12-17 13:29:25 -08:00
"github.com/hashicorp/packer-plugin-sdk/multistep/commonsteps"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
2015-06-14 11:23:29 -07:00
)
func testConfig () map [ string ] interface {} {
return map [ string ] interface {}{
"inline" : [] interface {}{ "foo" , "bar" },
}
}
func TestProvisionerPrepare_extractScript ( t * testing . T ) {
config := testConfig ()
p := new ( Provisioner )
_ = p . Prepare ( config )
file , err := extractScript ( p )
2018-04-25 23:51:46 +01:00
defer os . Remove ( file )
2015-06-14 11:23:29 -07:00
if err != nil {
t . Fatalf ( "Should not be error: %s" , err )
}
log . Printf ( "File: %s" , file )
if strings . Index ( file , os . TempDir ()) != 0 {
t . Fatalf ( "Temp file should reside in %s. File location: %s" , os . TempDir (), file )
}
// File contents should contain 2 lines concatenated by newlines: foo\nbar
2023-09-22 15:44:03 +08:00
readFile , err := os . ReadFile ( file )
2017-08-07 13:20:01 -04:00
if err != nil {
t . Fatalf ( "Should not be error: %s" , err )
}
2015-06-14 11:23:29 -07:00
expectedContents := "foo\nbar\n"
s := string ( readFile [:])
if s != expectedContents {
t . Fatalf ( "Expected generated inlineScript to equal '%s', got '%s'" , expectedContents , s )
}
}
func TestProvisioner_Impl ( t * testing . T ) {
var raw interface {}
raw = & Provisioner {}
2020-12-01 14:25:14 -08:00
if _ , ok := raw .( packersdk . Provisioner ); ! ok {
2015-06-14 11:23:29 -07:00
t . Fatalf ( "must be a Provisioner" )
}
}
func TestProvisionerPrepare_Defaults ( t * testing . T ) {
var p Provisioner
config := testConfig ()
err := p . Prepare ( config )
if err != nil {
t . Fatalf ( "err: %s" , err )
}
if p . config . RemotePath != DefaultRemotePath {
t . Errorf ( "unexpected remote path: %s" , p . config . RemotePath )
}
if p . config . ExecuteCommand != "{{.Vars}}\"{{.Path}}\"" {
t . Fatalf ( "Default command should be powershell {{.Vars}}\"{{.Path}}\", but got %s" , p . config . ExecuteCommand )
}
}
func TestProvisionerPrepare_Config ( t * testing . T ) {
}
func TestProvisionerPrepare_InvalidKey ( t * testing . T ) {
var p Provisioner
config := testConfig ()
// Add a random key
config [ "i_should_not_be_valid" ] = true
err := p . Prepare ( config )
if err == nil {
t . Fatal ( "should have error" )
}
}
func TestProvisionerPrepare_Script ( t * testing . T ) {
config := testConfig ()
delete ( config , "inline" )
config [ "script" ] = "/this/should/not/exist"
p := new ( Provisioner )
err := p . Prepare ( config )
if err == nil {
t . Fatal ( "should have error" )
}
// Test with a good one
2023-09-22 15:44:03 +08:00
tf , err := os . CreateTemp ( "" , "packer" )
2015-06-14 11:23:29 -07:00
if err != nil {
t . Fatalf ( "error tempfile: %s" , err )
}
defer os . Remove ( tf . Name ())
2018-04-25 23:51:46 +01:00
defer tf . Close ()
2015-06-14 11:23:29 -07:00
config [ "script" ] = tf . Name ()
p = new ( Provisioner )
err = p . Prepare ( config )
if err != nil {
t . Fatalf ( "should not have error: %s" , err )
}
}
func TestProvisionerPrepare_ScriptAndInline ( t * testing . T ) {
var p Provisioner
config := testConfig ()
delete ( config , "inline" )
delete ( config , "script" )
err := p . Prepare ( config )
if err == nil {
t . Fatal ( "should have error" )
}
// Test with both
2023-09-22 15:44:03 +08:00
tf , err := os . CreateTemp ( "" , "packer" )
2015-06-14 11:23:29 -07:00
if err != nil {
t . Fatalf ( "error tempfile: %s" , err )
}
defer os . Remove ( tf . Name ())
2018-04-25 23:51:46 +01:00
defer tf . Close ()
2015-06-14 11:23:29 -07:00
config [ "inline" ] = [] interface {}{ "foo" }
config [ "script" ] = tf . Name ()
err = p . Prepare ( config )
if err == nil {
t . Fatal ( "should have error" )
}
}
func TestProvisionerPrepare_ScriptAndScripts ( t * testing . T ) {
var p Provisioner
config := testConfig ()
// Test with both
2023-09-22 15:44:03 +08:00
tf , err := os . CreateTemp ( "" , "packer" )
2015-06-14 11:23:29 -07:00
if err != nil {
t . Fatalf ( "error tempfile: %s" , err )
}
defer os . Remove ( tf . Name ())
2018-04-25 23:51:46 +01:00
defer tf . Close ()
2015-06-14 11:23:29 -07:00
config [ "inline" ] = [] interface {}{ "foo" }
config [ "scripts" ] = [] string { tf . Name ()}
err = p . Prepare ( config )
if err == nil {
t . Fatal ( "should have error" )
}
}
func TestProvisionerPrepare_Scripts ( t * testing . T ) {
config := testConfig ()
delete ( config , "inline" )
config [ "scripts" ] = [] string {}
p := new ( Provisioner )
err := p . Prepare ( config )
if err == nil {
t . Fatal ( "should have error" )
}
// Test with a good one
2023-09-22 15:44:03 +08:00
tf , err := os . CreateTemp ( "" , "packer" )
2015-06-14 11:23:29 -07:00
if err != nil {
t . Fatalf ( "error tempfile: %s" , err )
}
defer os . Remove ( tf . Name ())
2018-04-25 23:51:46 +01:00
defer tf . Close ()
2015-06-14 11:23:29 -07:00
config [ "scripts" ] = [] string { tf . Name ()}
p = new ( Provisioner )
err = p . Prepare ( config )
if err != nil {
t . Fatalf ( "should not have error: %s" , err )
}
}
func TestProvisionerPrepare_EnvironmentVars ( t * testing . T ) {
config := testConfig ()
// Test with a bad case
config [ "environment_vars" ] = [] string { "badvar" , "good=var" }
p := new ( Provisioner )
err := p . Prepare ( config )
if err == nil {
t . Fatal ( "should have error" )
}
// Test with a trickier case
config [ "environment_vars" ] = [] string { "=bad" }
p = new ( Provisioner )
err = p . Prepare ( config )
if err == nil {
t . Fatal ( "should have error" )
}
// Test with a good case
// Note: baz= is a real env variable, just empty
config [ "environment_vars" ] = [] string { "FOO=bar" , "baz=" }
p = new ( Provisioner )
err = p . Prepare ( config )
if err != nil {
t . Fatalf ( "should not have error: %s" , err )
}
2017-01-19 12:12:00 +00:00
2017-01-18 12:51:14 -08:00
// Test when the env variable value contains an equals sign
config [ "environment_vars" ] = [] string { "good=withequals=true" }
p = new ( Provisioner )
err = p . Prepare ( config )
if err != nil {
t . Fatalf ( "should not have error: %s" , err )
}
// Test when the env variable value starts with an equals sign
config [ "environment_vars" ] = [] string { "good==true" }
p = new ( Provisioner )
err = p . Prepare ( config )
if err != nil {
t . Fatalf ( "should not have error: %s" , err )
}
2015-06-14 11:23:29 -07:00
}
func TestProvisionerQuote_EnvironmentVars ( t * testing . T ) {
config := testConfig ()
2017-01-18 12:51:14 -08:00
config [ "environment_vars" ] = [] string {
"keyone=valueone" ,
"keytwo=value\ntwo" ,
"keythree='valuethree'" ,
"keyfour='value\nfour'" ,
"keyfive='value=five'" ,
"keysix='=six'" ,
}
expected := [] string {
"keyone=valueone" ,
"keytwo=value\ntwo" ,
"keythree='valuethree'" ,
"keyfour='value\nfour'" ,
"keyfive='value=five'" ,
"keysix='=six'" ,
}
2015-06-14 11:23:29 -07:00
p := new ( Provisioner )
p . Prepare ( config )
2017-01-18 12:51:14 -08:00
for i , expectedValue := range expected {
if p . config . Vars [ i ] != expectedValue {
2017-01-19 12:12:00 +00:00
t . Fatalf ( "%s should be equal to %s" , p . config . Vars [ i ], expectedValue )
2017-01-18 12:51:14 -08:00
}
2015-06-14 11:23:29 -07:00
}
}
2020-11-20 10:21:29 -08:00
func testUi () * packersdk . BasicUi {
return & packersdk . BasicUi {
2015-06-14 11:23:29 -07:00
Reader : new ( bytes . Buffer ),
Writer : new ( bytes . Buffer ),
ErrorWriter : new ( bytes . Buffer ),
}
}
func TestProvisionerProvision_Inline ( t * testing . T ) {
config := testConfig ()
delete ( config , "inline" )
// Defaults provided by Packer
config [ "remote_path" ] = "c:/Windows/Temp/inlineScript.bat"
config [ "inline" ] = [] string { "whoami" }
ui := testUi ()
p := new ( Provisioner )
// Defaults provided by Packer
p . config . PackerBuildName = "vmware"
p . config . PackerBuilderType = "iso"
2020-11-20 10:21:29 -08:00
comm := new ( packersdk . MockCommunicator )
2015-06-14 11:23:29 -07:00
p . Prepare ( config )
2020-05-19 11:49:48 +02:00
err := p . Provision ( context . Background (), ui , comm , generatedData ())
2015-06-14 11:23:29 -07:00
if err != nil {
t . Fatal ( "should not have error" )
}
expectedCommand := `set "PACKER_BUILDER_TYPE=iso" && set "PACKER_BUILD_NAME=vmware" && "c:/Windows/Temp/inlineScript.bat"`
// Should run the command without alteration
if comm . StartCmd . Command != expectedCommand {
t . Fatalf ( "Expect command to be: %s, got %s" , expectedCommand , comm . StartCmd . Command )
}
envVars := make ([] string , 2 )
envVars [ 0 ] = "FOO=BAR"
envVars [ 1 ] = "BAR=BAZ"
config [ "environment_vars" ] = envVars
config [ "remote_path" ] = "c:/Windows/Temp/inlineScript.bat"
p . Prepare ( config )
2020-05-19 11:49:48 +02:00
err = p . Provision ( context . Background (), ui , comm , generatedData ())
2015-06-14 11:23:29 -07:00
if err != nil {
t . Fatal ( "should not have error" )
}
expectedCommand = `set "BAR=BAZ" && set "FOO=BAR" && set "PACKER_BUILDER_TYPE=iso" && set "PACKER_BUILD_NAME=vmware" && "c:/Windows/Temp/inlineScript.bat"`
// Should run the command without alteration
if comm . StartCmd . Command != expectedCommand {
t . Fatalf ( "Expect command to be: %s, got: %s" , expectedCommand , comm . StartCmd . Command )
}
}
func TestProvisionerProvision_Scripts ( t * testing . T ) {
2023-09-22 15:44:03 +08:00
tf , err := os . CreateTemp ( "" , "packer" )
2018-04-25 23:51:46 +01:00
if err != nil {
t . Fatalf ( "error tempfile: %s" , err )
}
defer os . Remove ( tf . Name ())
defer tf . Close ()
2015-06-14 11:23:29 -07:00
config := testConfig ()
delete ( config , "inline" )
2018-04-25 23:51:46 +01:00
config [ "scripts" ] = [] string { tf . Name ()}
2015-06-14 11:23:29 -07:00
config [ "packer_build_name" ] = "foobuild"
config [ "packer_builder_type" ] = "footype"
ui := testUi ()
p := new ( Provisioner )
2020-11-20 10:21:29 -08:00
comm := new ( packersdk . MockCommunicator )
2015-06-14 11:23:29 -07:00
p . Prepare ( config )
2020-05-19 11:49:48 +02:00
err = p . Provision ( context . Background (), ui , comm , generatedData ())
2015-06-14 11:23:29 -07:00
if err != nil {
t . Fatal ( "should not have error" )
}
//powershell -Command "$env:PACKER_BUILDER_TYPE=''"; powershell -Command "$env:PACKER_BUILD_NAME='foobuild'"; powershell -Command c:/Windows/Temp/script.ps1
expectedCommand := `set "PACKER_BUILDER_TYPE=footype" && set "PACKER_BUILD_NAME=foobuild" && "c:/Windows/Temp/script.bat"`
// Should run the command without alteration
if comm . StartCmd . Command != expectedCommand {
t . Fatalf ( "Expect command to be %s NOT %s" , expectedCommand , comm . StartCmd . Command )
}
}
func TestProvisionerProvision_ScriptsWithEnvVars ( t * testing . T ) {
2023-09-22 15:44:03 +08:00
tf , err := os . CreateTemp ( "" , "packer" )
2018-04-25 23:51:46 +01:00
if err != nil {
t . Fatalf ( "error tempfile: %s" , err )
}
defer os . Remove ( tf . Name ())
defer tf . Close ()
2015-06-14 11:23:29 -07:00
config := testConfig ()
ui := testUi ()
delete ( config , "inline" )
2018-04-25 23:51:46 +01:00
config [ "scripts" ] = [] string { tf . Name ()}
2015-06-14 11:23:29 -07:00
config [ "packer_build_name" ] = "foobuild"
config [ "packer_builder_type" ] = "footype"
// Env vars - currently should not effect them
envVars := make ([] string , 2 )
envVars [ 0 ] = "FOO=BAR"
envVars [ 1 ] = "BAR=BAZ"
config [ "environment_vars" ] = envVars
p := new ( Provisioner )
2020-11-20 10:21:29 -08:00
comm := new ( packersdk . MockCommunicator )
2015-06-14 11:23:29 -07:00
p . Prepare ( config )
2020-05-19 11:49:48 +02:00
err = p . Provision ( context . Background (), ui , comm , generatedData ())
2015-06-14 11:23:29 -07:00
if err != nil {
t . Fatal ( "should not have error" )
}
expectedCommand := `set "BAR=BAZ" && set "FOO=BAR" && set "PACKER_BUILDER_TYPE=footype" && set "PACKER_BUILD_NAME=foobuild" && "c:/Windows/Temp/script.bat"`
// Should run the command without alteration
if comm . StartCmd . Command != expectedCommand {
t . Fatalf ( "Expect command to be %s NOT %s" , expectedCommand , comm . StartCmd . Command )
}
}
func TestProvisioner_createFlattenedEnvVars_windows ( t * testing . T ) {
2017-01-23 12:08:17 +00:00
var flattenedEnvVars string
2015-06-14 11:23:29 -07:00
config := testConfig ()
2017-01-23 12:08:17 +00:00
userEnvVarTests := [][] string {
{}, // No user env var
{ "FOO=bar" }, // Single user env var
{ "FOO=bar" , "BAZ=qux" }, // Multiple user env vars
{ "FOO=bar=baz" }, // User env var with value containing equals
{ "FOO==bar" }, // User env var with value starting with equals
2015-06-14 11:23:29 -07:00
}
2022-05-31 09:49:38 -04:00
userEnvVarmapTests := [] map [ string ] string {
{},
{
"BAR" : "foo" ,
},
{
"BAR" : "foo" ,
"YAR" : "yaa" ,
},
{
"BAR" : "foo=yar" ,
},
{
"BAR" : "=foo" ,
},
}
2017-01-23 12:08:17 +00:00
expected := [] string {
`set "PACKER_BUILDER_TYPE=iso" && set "PACKER_BUILD_NAME=vmware" && ` ,
2022-05-31 09:49:38 -04:00
`set "BAR=foo" && set "FOO=bar" && set "PACKER_BUILDER_TYPE=iso" && set "PACKER_BUILD_NAME=vmware" && ` ,
`set "BAR=foo" && set "BAZ=qux" && set "FOO=bar" && set "PACKER_BUILDER_TYPE=iso" && set "PACKER_BUILD_NAME=vmware" && set "YAR=yaa" && ` ,
`set "BAR=foo=yar" && set "FOO=bar=baz" && set "PACKER_BUILDER_TYPE=iso" && set "PACKER_BUILD_NAME=vmware" && ` ,
`set "BAR==foo" && set "FOO==bar" && set "PACKER_BUILDER_TYPE=iso" && set "PACKER_BUILD_NAME=vmware" && ` ,
2017-01-23 12:08:17 +00:00
}
p := new ( Provisioner )
2020-05-19 11:49:48 +02:00
p . generatedData = generatedData ()
2017-01-23 12:08:17 +00:00
p . Prepare ( config )
2015-06-14 11:23:29 -07:00
// Defaults provided by Packer
p . config . PackerBuildName = "vmware"
p . config . PackerBuilderType = "iso"
2017-01-23 12:08:17 +00:00
for i , expectedValue := range expected {
p . config . Vars = userEnvVarTests [ i ]
2022-05-31 09:49:38 -04:00
p . config . Env = userEnvVarmapTests [ i ]
2017-01-23 12:08:17 +00:00
flattenedEnvVars = p . createFlattenedEnvVars ()
if flattenedEnvVars != expectedValue {
t . Fatalf ( "expected flattened env vars to be: %s, got %s." , expectedValue , flattenedEnvVars )
}
2015-06-14 11:23:29 -07:00
}
}
2020-05-19 11:49:48 +02:00
2015-06-14 11:23:29 -07:00
func TestCancel ( t * testing . T ) {
// Don't actually call Cancel() as it performs an os.Exit(0)
// which kills the 'go test' tool
}
2020-05-19 11:49:48 +02:00
func generatedData () map [ string ] interface {} {
return map [ string ] interface {}{
2020-11-11 15:04:28 -08:00
"PackerHTTPAddr" : commonsteps . HttpAddrNotImplemented ,
"PackerHTTPIP" : commonsteps . HttpIPNotImplemented ,
"PackerHTTPPort" : commonsteps . HttpPortNotImplemented ,
2020-05-19 11:49:48 +02:00
}
}