Skip to content

Commit

Permalink
Merge pull request #1469 from openziti/fix.config.template.tests
Browse files Browse the repository at this point in the history
fixes template config tests on windows due to Stdout backpressure
  • Loading branch information
andrewpmartinez authored Oct 26, 2023
2 parents 8ec26ef + dd9b04b commit a698172
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 6 deletions.
4 changes: 3 additions & 1 deletion ziti/cmd/create/create_config_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,12 @@ func (options *CreateConfigControllerOptions) run(data *ConfigTemplateValues) er
if err != nil {
return errors.Wrapf(err, "unable to create config file: %s", options.Output)
}

//only close things we open
defer func() { _ = f.Close() }()
} else {
f = os.Stdout
}
defer func() { _ = f.Close() }()

if err := tmpl.Execute(f, data); err != nil {
return errors.Wrap(err, "unable to execute template")
Expand Down
52 changes: 47 additions & 5 deletions ziti/cmd/create/create_config_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package create

import (
"bytes"
"fmt"
"github.com/stretchr/testify/assert"
"io"
Expand Down Expand Up @@ -247,18 +246,61 @@ func contains(s []string, str string) bool {
return false
}

// captureOutput hot-swaps os.Stdout in order to redirect all output to a memory buffer. Where possible, do not use
// this function and instead create optional arguments/configuration to redirect output to io.Writer instances. This
// should only be used for functionality that we do not control. Many instances of its usage are unnecessary and should
// be remedied with the aforementioned solution where possible.
func captureOutput(function func()) string {
var buffer bytes.Buffer
oldStdOut := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w

defer func() {
_ = r.Close()
}()

type readResult struct {
out []byte
err error
}

defer func() {
os.Stdout = oldStdOut
}()

var output []byte
var outputErr error

outChan := make(chan *readResult, 1)

// Start reading before writing, so we do not create backpressure that is never relieved in OSs with smaller buffers
// than the resulting configuration file (i.e. Windows). Go will not yield to other routines unless there is
// a system call. The fake os.Stdout will never yield and some code paths executed as `function()` may not
// have syscalls.
go func() {
output, outputErr = io.ReadAll(r)
outChan <- &readResult{
output,
outputErr,
}
}()

function()

_ = w.Close()
os.Stdout = oldStdOut
_, _ = io.Copy(&buffer, r)
return buffer.String()
_ = w.Close()

result := <-outChan

if result == nil {
panic("no output")
}

if result.err != nil {
panic(result.err)
}

return string(result.out)
}

func setEnvByMap[K string, V string](m map[K]V) {
Expand Down

0 comments on commit a698172

Please sign in to comment.