-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tbot configure
command for assisting Machine ID configuration (#12517)
* add `tbot configure` command * introduce golden file test helper * address PR comments by zmb
- Loading branch information
1 parent
bc09235
commit 2f00cb4
Showing
8 changed files
with
349 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
/* | ||
Copyright 2022 Gravitational, Inc. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
// Golden files are a convenient way of storing data that we want to assert in | ||
// unit tests. They are stored under the `testdata/` directory in a directory | ||
// based on the name of the test. They are especially useful for storing large | ||
// pieces of data that can be unwieldy to embed directly into your test tables. | ||
// | ||
// The convenience factor comes from the update mode which causes the tests to | ||
// write data, rather than assert against it. This allows expected outputs | ||
// to be updated easily when the underlying implementation is adjusted. | ||
// This mode can be enabled by setting `GOLDEN_UPDATE=1` when running the tests | ||
// you wish to update. | ||
// | ||
// Usage: | ||
// | ||
// Golden is ideal for testing the results of marshalling, or units that output | ||
// large amounts of data to stdout or a file: | ||
// | ||
// func TestMarshalFooStruct(t *testing.T) { | ||
// got, err := json.Marshal(FooStruct{Some: "Data"}) | ||
// require.NoError(t, err) | ||
// | ||
// if golden.Update() { | ||
// golden.Set(t, got) | ||
// } | ||
// require.Equal(t, golden.Get(t), got) | ||
// } | ||
// | ||
// It is possible to have multiple golden files per test using `GetNamed` and | ||
// `SetNamed`. This is useful for cases where your unit under test produces | ||
// multiple pieces of output e.g stdout and stderr: | ||
// | ||
// func TestFooCommand(t *testing.T) { | ||
// stdoutBuf := new(bytes.Buffer) | ||
// stderrBuf := new(bytes.Buffer) | ||
// | ||
// FooCommand(stdoutBuf, stderrBuf) | ||
// | ||
// stdout := stdoutBuf.Bytes() | ||
// stderr := stderrBuf.Bytes() | ||
// | ||
// if golden.Update() { | ||
// golden.SetNamed(t, "stdout", stdout) | ||
// golden.SetNamed(t, "stderr", stderr) | ||
// } | ||
// require.Equal(t, golden.GetNamed(t, "stdout"), stdout) | ||
// require.Equal(t, golden.GetNamed(t, "stderr"), stderr) | ||
// } | ||
|
||
package golden | ||
|
||
import ( | ||
"os" | ||
"path/filepath" | ||
"strconv" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func pathForFile(t *testing.T, name string) string { | ||
pathComponents := []string{ | ||
"testdata", | ||
t.Name(), | ||
} | ||
|
||
if name != "" { | ||
pathComponents = append(pathComponents, name) | ||
} | ||
|
||
return filepath.Join(pathComponents...) + ".golden" | ||
} | ||
|
||
// ShouldSet provides a boolean value that indicates if your code should then | ||
// call `Set` or `SetNamed` to update the stored golden file value with new | ||
// data. | ||
func ShouldSet() bool { | ||
env := os.Getenv("GOLDEN_UPDATE") | ||
should, _ := strconv.ParseBool(env) | ||
return should | ||
} | ||
|
||
// SetNamed writes the supplied data to a named golden file for the current | ||
// test. | ||
func SetNamed(t *testing.T, name string, data []byte) { | ||
p := pathForFile(t, name) | ||
dir := filepath.Dir(p) | ||
|
||
err := os.MkdirAll(dir, 0o755) | ||
require.NoError(t, err) | ||
|
||
err = os.WriteFile(p, data, 0o644) | ||
require.NoError(t, err) | ||
} | ||
|
||
// Set writes the supplied data to the golden file for the current test. | ||
func Set(t *testing.T, data []byte) { | ||
SetNamed(t, "", data) | ||
} | ||
|
||
// GetNamed returns the contents of a named golden file for the current test. If | ||
// the specified golden file does not exist for the test, the test will be | ||
// failed. | ||
func GetNamed(t *testing.T, name string) []byte { | ||
p := pathForFile(t, name) | ||
data, err := os.ReadFile(p) | ||
require.NoError(t, err) | ||
|
||
return data | ||
} | ||
|
||
// Get returns the contents of the golden file for the current test. If there is | ||
// no golden file for the test, the test will be failed. | ||
func Get(t *testing.T) []byte { | ||
return GetNamed(t, "") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/* | ||
Copyright 2022 Gravitational, Inc. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
package main | ||
|
||
import ( | ||
"bytes" | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/gravitational/teleport/lib/utils/golden" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestRun_Configure(t *testing.T) { | ||
t.Parallel() | ||
|
||
// This is slightly rubbish, but due to the global nature of `botfs`, | ||
// it's difficult to configure the default acl and symlink values to be | ||
// the same across dev laptops and GCB. | ||
// If we switch to a more dependency injected model for botfs, we can | ||
// ensure that the test one returns the same value across operating systems. | ||
normalizeOSDependentValues := func(data []byte) []byte { | ||
cpy := append([]byte{}, data...) | ||
cpy = bytes.ReplaceAll( | ||
cpy, []byte("symlinks: try-secure"), []byte("symlinks: secure"), | ||
) | ||
cpy = bytes.ReplaceAll( | ||
cpy, []byte(`acls: "off"`), []byte("acls: try"), | ||
) | ||
return cpy | ||
} | ||
|
||
baseArgs := []string{"configure"} | ||
tests := []struct { | ||
name string | ||
args []string | ||
}{ | ||
{ | ||
name: "no parameters provided", | ||
args: baseArgs, | ||
}, | ||
{ | ||
name: "all parameters provided", | ||
args: append(baseArgs, []string{ | ||
"-a", "example.com", | ||
"--token", "xxyzz", | ||
"--ca-pin", "sha256:capindata", | ||
"--data-dir", "/custom/data/dir", | ||
"--join-method", "token", | ||
"--oneshot", | ||
"--certificate-ttl", "42m", | ||
"--renewal-interval", "21m", | ||
}...), | ||
}, | ||
} | ||
|
||
for _, tt := range tests { | ||
tt := tt | ||
t.Run(tt.name, func(t *testing.T) { | ||
t.Run("file", func(t *testing.T) { | ||
path := filepath.Join(t.TempDir(), "config.yaml") | ||
args := append(tt.args, []string{"-o", path}...) | ||
err := Run(args, nil) | ||
require.NoError(t, err) | ||
|
||
data, err := os.ReadFile(path) | ||
data = normalizeOSDependentValues(data) | ||
require.NoError(t, err) | ||
if golden.ShouldSet() { | ||
golden.Set(t, data) | ||
} | ||
require.Equal(t, string(golden.Get(t)), string(data)) | ||
}) | ||
|
||
t.Run("stdout", func(t *testing.T) { | ||
stdout := new(bytes.Buffer) | ||
err := Run(tt.args, stdout) | ||
require.NoError(t, err) | ||
data := normalizeOSDependentValues(stdout.Bytes()) | ||
if golden.ShouldSet() { | ||
golden.Set(t, data) | ||
} | ||
require.Equal(t, string(golden.Get(t)), string(data)) | ||
}) | ||
}) | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
tool/tbot/testdata/TestRun_Configure/all_parameters_provided/file.golden
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# tbot config file generated by `configure` command | ||
onboarding: | ||
token: xxyzz | ||
ca_path: "" | ||
ca_pins: | ||
- sha256:capindata | ||
join_method: token | ||
storage: | ||
directory: | ||
path: /custom/data/dir | ||
symlinks: secure | ||
acls: try | ||
debug: false | ||
auth_server: example.com | ||
certificate_ttl: 42m0s | ||
renewal_interval: 21m0s | ||
oneshot: true |
Oops, something went wrong.