github.com/hashicorp/packer@v1.14.3/packer/ui_test.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package packer
     5  
     6  import (
     7  	"bytes"
     8  	"strings"
     9  	"testing"
    10  
    11  	packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
    12  )
    13  
    14  // This reads the output from the bytes.Buffer in our test object
    15  // and then resets the buffer.
    16  func readWriter(ui *packersdk.BasicUi) (result string) {
    17  	buffer := ui.Writer.(*bytes.Buffer)
    18  	result = buffer.String()
    19  	buffer.Reset()
    20  	return
    21  }
    22  
    23  // Reset the input Reader than add some input to it.
    24  func writeReader(ui *packersdk.BasicUi, input string) {
    25  	buffer := ui.Reader.(*bytes.Buffer)
    26  	buffer.WriteString(input)
    27  }
    28  
    29  func readErrorWriter(ui *packersdk.BasicUi) (result string) {
    30  	buffer := ui.ErrorWriter.(*bytes.Buffer)
    31  	result = buffer.String()
    32  	buffer.Reset()
    33  	return
    34  }
    35  
    36  func testUi() *packersdk.BasicUi {
    37  	return &packersdk.BasicUi{
    38  		Reader:      new(bytes.Buffer),
    39  		Writer:      new(bytes.Buffer),
    40  		ErrorWriter: new(bytes.Buffer),
    41  		TTY:         new(testTTY),
    42  	}
    43  }
    44  
    45  type testTTY struct {
    46  	say string
    47  }
    48  
    49  func (tty *testTTY) Close() error { return nil }
    50  func (tty *testTTY) ReadString() (string, error) {
    51  	return tty.say, nil
    52  }
    53  
    54  func TestColoredUi(t *testing.T) {
    55  	bufferUi := testUi()
    56  	ui := &ColoredUi{UiColorYellow, UiColorRed, bufferUi, &UiProgressBar{}}
    57  
    58  	if !ui.supportsColors() {
    59  		t.Skip("skipping for ui without color support")
    60  	}
    61  
    62  	ui.Say("foo")
    63  	result := readWriter(bufferUi)
    64  	if result != "\033[1;33mfoo\033[0m\n" {
    65  		t.Fatalf("invalid output: %s", result)
    66  	}
    67  
    68  	ui.Message("foo")
    69  	result = readWriter(bufferUi)
    70  	if result != "\033[1;33mfoo\033[0m\n" {
    71  		t.Fatalf("invalid output: %s", result)
    72  	}
    73  
    74  	ui.Error("foo")
    75  	result = readWriter(bufferUi)
    76  	if result != "" {
    77  		t.Fatalf("invalid output: %s", result)
    78  	}
    79  
    80  	result = readErrorWriter(bufferUi)
    81  	if result != "\033[1;31mfoo\033[0m\n" {
    82  		t.Fatalf("invalid output: %s", result)
    83  	}
    84  }
    85  
    86  func TestColoredUi_noColorEnv(t *testing.T) {
    87  	bufferUi := testUi()
    88  	ui := &ColoredUi{UiColorYellow, UiColorRed, bufferUi, &UiProgressBar{}}
    89  
    90  	// Set the env var to get rid of the color
    91  	t.Setenv("PACKER_NO_COLOR", "1")
    92  
    93  	ui.Say("foo")
    94  	result := readWriter(bufferUi)
    95  	if result != "foo\n" {
    96  		t.Fatalf("invalid output: %s", result)
    97  	}
    98  
    99  	ui.Message("foo")
   100  	result = readWriter(bufferUi)
   101  	if result != "foo\n" {
   102  		t.Fatalf("invalid output: %s", result)
   103  	}
   104  
   105  	ui.Error("foo")
   106  	result = readErrorWriter(bufferUi)
   107  	if result != "foo\n" {
   108  		t.Fatalf("invalid output: %s", result)
   109  	}
   110  }
   111  
   112  func TestTargetedUI(t *testing.T) {
   113  	bufferUi := testUi()
   114  	targetedUi := &TargetedUI{
   115  		Target: "foo",
   116  		Ui:     bufferUi,
   117  	}
   118  
   119  	var actual, expected string
   120  	targetedUi.Say("foo")
   121  	actual = readWriter(bufferUi)
   122  	expected = "==> foo: foo\n"
   123  	if actual != expected {
   124  		t.Fatalf("bad: %#v", actual)
   125  	}
   126  
   127  	targetedUi.Message("foo")
   128  	actual = readWriter(bufferUi)
   129  	expected = "==> foo: foo\n"
   130  	if actual != expected {
   131  		t.Fatalf("bad: %#v", actual)
   132  	}
   133  
   134  	targetedUi.Error("bar")
   135  	actual = readErrorWriter(bufferUi)
   136  	expected = "==> foo: bar\n"
   137  	if actual != expected {
   138  		t.Fatalf("bad: %#v", actual)
   139  	}
   140  
   141  	targetedUi.Say("foo\nbar")
   142  	actual = readWriter(bufferUi)
   143  	expected = "==> foo: foo\n==> foo: bar\n"
   144  	if actual != expected {
   145  		t.Fatalf("bad: %#v", actual)
   146  	}
   147  }
   148  
   149  func TestColoredUi_ImplUi(t *testing.T) {
   150  	var raw interface{}
   151  	raw = &ColoredUi{}
   152  	if _, ok := raw.(packersdk.Ui); !ok {
   153  		t.Fatalf("ColoredUi must implement Ui")
   154  	}
   155  }
   156  
   157  func TestTargetedUI_ImplUi(t *testing.T) {
   158  	var raw interface{}
   159  	raw = &TargetedUI{}
   160  	if _, ok := raw.(packersdk.Ui); !ok {
   161  		t.Fatalf("TargetedUI must implement Ui")
   162  	}
   163  }
   164  
   165  func TestBasicUi_ImplUi(t *testing.T) {
   166  	var raw interface{}
   167  	raw = &packersdk.BasicUi{}
   168  	if _, ok := raw.(packersdk.Ui); !ok {
   169  		t.Fatalf("BasicUi must implement Ui")
   170  	}
   171  }
   172  
   173  func TestBasicUi_Error(t *testing.T) {
   174  	bufferUi := testUi()
   175  
   176  	var actual, expected string
   177  	bufferUi.Error("foo")
   178  	actual = readErrorWriter(bufferUi)
   179  	expected = "foo\n"
   180  	if actual != expected {
   181  		t.Fatalf("bad: %#v", actual)
   182  	}
   183  
   184  	bufferUi.ErrorWriter = nil
   185  	bufferUi.Error("5")
   186  	actual = readWriter(bufferUi)
   187  	expected = "5\n"
   188  	if actual != expected {
   189  		t.Fatalf("bad: %#v", actual)
   190  	}
   191  }
   192  
   193  func TestBasicUi_Say(t *testing.T) {
   194  	bufferUi := testUi()
   195  
   196  	var actual, expected string
   197  
   198  	bufferUi.Say("foo")
   199  	actual = readWriter(bufferUi)
   200  	expected = "foo\n"
   201  	if actual != expected {
   202  		t.Fatalf("bad: %#v", actual)
   203  	}
   204  
   205  	bufferUi.Say("5")
   206  	actual = readWriter(bufferUi)
   207  	expected = "5\n"
   208  	if actual != expected {
   209  		t.Fatalf("bad: %#v", actual)
   210  	}
   211  }
   212  
   213  func TestBasicUi_Ask(t *testing.T) {
   214  
   215  	var actual, expected string
   216  	var err error
   217  
   218  	var testCases = []struct {
   219  		Prompt, Input, Answer string
   220  	}{
   221  		{"[c]ontinue or [a]bort", "c\n", "c"},
   222  		{"[c]ontinue or [a]bort", "c", "c"},
   223  		// Empty input shouldn't give an error
   224  		{"Name", "Joe Bloggs\n", "Joe Bloggs"},
   225  		{"Name", "Joe Bloggs", "Joe Bloggs"},
   226  		{"Name", "\n", ""},
   227  	}
   228  
   229  	for _, testCase := range testCases {
   230  		// Because of the internal bufio we can't easily reset the input, so create a new one each time
   231  		bufferUi := testUi()
   232  		bufferUi.TTY = &testTTY{testCase.Input}
   233  
   234  		actual, err = bufferUi.Ask(testCase.Prompt)
   235  		if err != nil {
   236  			t.Fatal(err)
   237  		}
   238  
   239  		if actual != testCase.Answer {
   240  			t.Fatalf("bad answer: %#v", actual)
   241  		}
   242  
   243  		actual = readWriter(bufferUi)
   244  		expected = testCase.Prompt + " "
   245  		if actual != expected {
   246  			t.Fatalf("bad prompt: %#v", actual)
   247  		}
   248  	}
   249  
   250  }
   251  
   252  func TestMachineReadableUi_ImplUi(t *testing.T) {
   253  	var raw interface{}
   254  	raw = &MachineReadableUi{}
   255  	if _, ok := raw.(packersdk.Ui); !ok {
   256  		t.Fatalf("MachineReadableUi must implement Ui")
   257  	}
   258  }
   259  
   260  func TestMachineReadableUi(t *testing.T) {
   261  	var data, expected string
   262  
   263  	buf := new(bytes.Buffer)
   264  	ui := &MachineReadableUi{Writer: buf}
   265  
   266  	// No target
   267  	ui.Machine("foo", "bar", "baz")
   268  	data = strings.SplitN(buf.String(), ",", 2)[1]
   269  	expected = ",foo,bar,baz\n"
   270  	if data != expected {
   271  		t.Fatalf("bad: %s", data)
   272  	}
   273  
   274  	// Target
   275  	buf.Reset()
   276  	ui.Machine("mitchellh,foo", "bar", "baz")
   277  	data = strings.SplitN(buf.String(), ",", 2)[1]
   278  	expected = "mitchellh,foo,bar,baz\n"
   279  	if data != expected {
   280  		t.Fatalf("bad: %s", data)
   281  	}
   282  
   283  	// Commas
   284  	buf.Reset()
   285  	ui.Machine("foo", "foo,bar")
   286  	data = strings.SplitN(buf.String(), ",", 2)[1]
   287  	expected = ",foo,foo%!(PACKER_COMMA)bar\n"
   288  	if data != expected {
   289  		t.Fatalf("bad: %s", data)
   290  	}
   291  
   292  	// New lines
   293  	buf.Reset()
   294  	ui.Machine("foo", "foo\n")
   295  	data = strings.SplitN(buf.String(), ",", 2)[1]
   296  	expected = ",foo,foo\\n\n"
   297  	if data != expected {
   298  		t.Fatalf("bad: %#v", data)
   299  	}
   300  }