github.com/buildpacks/pack@v0.33.3-0.20240516162812-884dd1837311/pkg/logging/prefix_writer_test.go (about)

     1  package logging_test
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"io"
     7  	"testing"
     8  
     9  	"github.com/heroku/color"
    10  	"github.com/sclevine/spec"
    11  	"github.com/sclevine/spec/report"
    12  
    13  	"github.com/buildpacks/pack/pkg/logging"
    14  	h "github.com/buildpacks/pack/testhelpers"
    15  )
    16  
    17  func TestPrefixWriter(t *testing.T) {
    18  	color.Disable(true)
    19  	defer color.Disable(false)
    20  	spec.Run(t, "PrefixWriter", testPrefixWriter, spec.Parallel(), spec.Report(report.Terminal{}))
    21  }
    22  
    23  func testPrefixWriter(t *testing.T, when spec.G, it spec.S) {
    24  	var (
    25  		assert = h.NewAssertionManager(t)
    26  	)
    27  
    28  	when("#Write", func() {
    29  		it("prepends prefix to string", func() {
    30  			var w bytes.Buffer
    31  
    32  			writer := logging.NewPrefixWriter(&w, "prefix")
    33  			_, err := writer.Write([]byte("test"))
    34  			assert.Nil(err)
    35  			err = writer.Close()
    36  			assert.Nil(err)
    37  
    38  			h.AssertEq(t, w.String(), "[prefix] test\n")
    39  		})
    40  
    41  		it("prepends prefix to multi-line string", func() {
    42  			var w bytes.Buffer
    43  
    44  			writer := logging.NewPrefixWriter(&w, "prefix")
    45  			_, err := writer.Write([]byte("line 1\nline 2\nline 3"))
    46  			assert.Nil(err)
    47  			err = writer.Close()
    48  			assert.Nil(err)
    49  
    50  			h.AssertEq(t, w.String(), "[prefix] line 1\n[prefix] line 2\n[prefix] line 3\n")
    51  		})
    52  
    53  		it("buffers mid-line calls", func() {
    54  			var buf bytes.Buffer
    55  
    56  			writer := logging.NewPrefixWriter(&buf, "prefix")
    57  			_, err := writer.Write([]byte("word 1, "))
    58  			assert.Nil(err)
    59  			_, err = writer.Write([]byte("word 2, "))
    60  			assert.Nil(err)
    61  			_, err = writer.Write([]byte("word 3."))
    62  			assert.Nil(err)
    63  			err = writer.Close()
    64  			assert.Nil(err)
    65  
    66  			h.AssertEq(t, buf.String(), "[prefix] word 1, word 2, word 3.\n")
    67  		})
    68  
    69  		it("handles empty lines", func() {
    70  			var buf bytes.Buffer
    71  
    72  			writer := logging.NewPrefixWriter(&buf, "prefix")
    73  			_, err := writer.Write([]byte("\n"))
    74  			assert.Nil(err)
    75  			err = writer.Close()
    76  			assert.Nil(err)
    77  
    78  			h.AssertEq(t, buf.String(), "[prefix] \n")
    79  		})
    80  
    81  		it("handles empty input", func() {
    82  			var buf bytes.Buffer
    83  
    84  			writer := logging.NewPrefixWriter(&buf, "prefix")
    85  			_, err := writer.Write([]byte(""))
    86  			assert.Nil(err)
    87  			err = writer.Close()
    88  			assert.Nil(err)
    89  
    90  			assert.Equal(buf.String(), "")
    91  		})
    92  
    93  		it("propagates reader errors", func() {
    94  			var buf bytes.Buffer
    95  
    96  			factory := &boobyTrapReaderFactory{failAtCallNumber: 2}
    97  			writer := logging.NewPrefixWriter(&buf, "prefix", logging.WithReaderFactory(factory.NewReader))
    98  			_, err := writer.Write([]byte("word 1,"))
    99  			assert.Nil(err)
   100  			_, err = writer.Write([]byte("word 2."))
   101  			assert.ErrorContains(err, "some error")
   102  		})
   103  
   104  		it("handles requests to clear line", func() {
   105  			var buf bytes.Buffer
   106  
   107  			writer := logging.NewPrefixWriter(&buf, "prefix")
   108  			_, err := writer.Write([]byte("progress 1\rprogress 2\rprogress 3\rcomplete!"))
   109  			assert.Nil(err)
   110  			err = writer.Close()
   111  			assert.Nil(err)
   112  
   113  			h.AssertEq(t, buf.String(), "[prefix] complete!\n")
   114  		})
   115  
   116  		it("handles requests clear line (amidst content)", func() {
   117  			var buf bytes.Buffer
   118  
   119  			writer := logging.NewPrefixWriter(&buf, "prefix")
   120  			_, err := writer.Write([]byte("downloading\rcompleted!      \r\nall done!\nnevermind\r"))
   121  			assert.Nil(err)
   122  			err = writer.Close()
   123  			assert.Nil(err)
   124  
   125  			h.AssertEq(t, buf.String(), "[prefix] completed!      \n[prefix] all done!\n[prefix] \n")
   126  		})
   127  	})
   128  }
   129  
   130  type boobyTrapReaderFactory struct {
   131  	numberOfCalls    int
   132  	failAtCallNumber int
   133  }
   134  
   135  func (b *boobyTrapReaderFactory) NewReader(data []byte) io.Reader {
   136  	b.numberOfCalls++
   137  	if b.numberOfCalls >= b.failAtCallNumber {
   138  		return &faultyReader{}
   139  	}
   140  
   141  	return bytes.NewReader(data)
   142  }
   143  
   144  type faultyReader struct {
   145  }
   146  
   147  func (f faultyReader) Read(b []byte) (n int, err error) {
   148  	return 0, errors.New("some error")
   149  }