-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: Ben Meier <[email protected]>
- Loading branch information
1 parent
88f20d4
commit 47edb1d
Showing
5 changed files
with
359 additions
and
6 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
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,152 @@ | ||
// Copyright 2024 Humanitec | ||
// | ||
// 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 ( | ||
"context" | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/score-spec/score-k8s/internal/project" | ||
) | ||
|
||
func changeToDir(t *testing.T, dir string) string { | ||
t.Helper() | ||
wd, _ := os.Getwd() | ||
require.NoError(t, os.Chdir(dir)) | ||
t.Cleanup(func() { | ||
require.NoError(t, os.Chdir(wd)) | ||
}) | ||
return dir | ||
} | ||
|
||
func changeToTempDir(t *testing.T) string { | ||
return changeToDir(t, t.TempDir()) | ||
} | ||
|
||
func TestGenerateWithoutInit(t *testing.T) { | ||
_ = changeToTempDir(t) | ||
stdout, _, err := executeAndResetCommand(context.Background(), rootCmd, []string{"generate"}) | ||
assert.EqualError(t, err, "state directory does not exist, please run \"score-k8s init\" first") | ||
assert.Equal(t, "", stdout) | ||
} | ||
|
||
func TestGenerateWithoutScoreFiles(t *testing.T) { | ||
_ = changeToTempDir(t) | ||
stdout, _, err := executeAndResetCommand(context.Background(), rootCmd, []string{"init"}) | ||
assert.NoError(t, err) | ||
assert.Equal(t, "", stdout) | ||
stdout, _, err = executeAndResetCommand(context.Background(), rootCmd, []string{"generate"}) | ||
assert.EqualError(t, err, "Project is empty, please add a score file") | ||
assert.Equal(t, "", stdout) | ||
} | ||
|
||
func TestInitAndGenerateWithBadFile(t *testing.T) { | ||
td := changeToTempDir(t) | ||
stdout, _, err := executeAndResetCommand(context.Background(), rootCmd, []string{"init"}) | ||
assert.NoError(t, err) | ||
assert.Equal(t, "", stdout) | ||
|
||
assert.NoError(t, os.WriteFile(filepath.Join(td, "thing"), []byte(`"blah"`), 0644)) | ||
|
||
stdout, _, err = executeAndResetCommand(context.Background(), rootCmd, []string{"generate", "thing"}) | ||
assert.EqualError(t, err, "failed to decode input score file: thing: yaml: unmarshal errors:\n line 1: cannot unmarshal !!str `blah` into map[string]interface {}") | ||
assert.Equal(t, "", stdout) | ||
} | ||
|
||
func TestInitAndGenerateWithBadScore(t *testing.T) { | ||
td := changeToTempDir(t) | ||
stdout, _, err := executeAndResetCommand(context.Background(), rootCmd, []string{"init"}) | ||
assert.NoError(t, err) | ||
assert.Equal(t, "", stdout) | ||
|
||
assert.NoError(t, os.WriteFile(filepath.Join(td, "thing"), []byte(`{}`), 0644)) | ||
|
||
stdout, _, err = executeAndResetCommand(context.Background(), rootCmd, []string{"generate", "thing"}) | ||
assert.EqualError(t, err, "invalid score file: thing: jsonschema: '' does not validate with https://score.dev/schemas/score#/required: missing properties: 'apiVersion', 'metadata', 'containers'") | ||
assert.Equal(t, "", stdout) | ||
} | ||
|
||
func TestInitAndGenerate_with_sample(t *testing.T) { | ||
td := changeToTempDir(t) | ||
stdout, _, err := executeAndResetCommand(context.Background(), rootCmd, []string{"init"}) | ||
require.NoError(t, err) | ||
assert.Equal(t, "", stdout) | ||
|
||
// write overrides file | ||
assert.NoError(t, os.WriteFile(filepath.Join(td, "overrides.yaml"), []byte(`{"resources": {"foo": {"type": "example-provisioner-resource"}}}`), 0644)) | ||
// generate | ||
stdout, _, err = executeAndResetCommand(context.Background(), rootCmd, []string{ | ||
"generate", "-o", "manifests.yaml", | ||
"--overrides-file", "overrides.yaml", | ||
"--override-property", "containers.main.variables.THING=${resources.foo.plaintext}", | ||
"--", "score.yaml", | ||
}) | ||
require.NoError(t, err) | ||
assert.Equal(t, "", stdout) | ||
raw, err := os.ReadFile(filepath.Join(td, "manifests.yaml")) | ||
assert.NoError(t, err) | ||
assert.Contains(t, string(raw), "\nkind: ConfigMap\n") | ||
assert.Contains(t, string(raw), "\nkind: Service\n") | ||
assert.Contains(t, string(raw), "\nkind: Deployment\n") | ||
|
||
// check that state was persisted | ||
sd, ok, err := project.LoadStateDirectory(td) | ||
assert.NoError(t, err) | ||
assert.True(t, ok) | ||
assert.Equal(t, "score.yaml", *sd.State.Workloads["example"].File) | ||
assert.Len(t, sd.State.Workloads, 1) | ||
assert.Len(t, sd.State.Resources, 1) | ||
} | ||
|
||
func TestInitAndGenerate_with_image_override(t *testing.T) { | ||
td := changeToTempDir(t) | ||
stdout, _, err := executeAndResetCommand(context.Background(), rootCmd, []string{"init"}) | ||
assert.NoError(t, err) | ||
assert.Equal(t, "", stdout) | ||
|
||
// write new score file | ||
assert.NoError(t, os.WriteFile(filepath.Join(td, "score.yaml"), []byte(` | ||
apiVersion: score.dev/v1b1 | ||
metadata: | ||
name: example | ||
containers: | ||
example: | ||
image: . | ||
`), 0644)) | ||
|
||
t.Run("generate but fail due to missing override", func(t *testing.T) { | ||
stdout, _, err = executeAndResetCommand(context.Background(), rootCmd, []string{ | ||
"generate", "-o", "manifests.yaml", "--", "score.yaml", | ||
}) | ||
assert.EqualError(t, err, "failed to convert 'score.yaml' because container 'example' has no image and --image was not provided") | ||
}) | ||
|
||
t.Run("generate with image", func(t *testing.T) { | ||
// generate with image | ||
stdout, _, err = executeAndResetCommand(context.Background(), rootCmd, []string{ | ||
"generate", "-o", "manifests.yaml", "--image", "busybox:latest", "--", "score.yaml", | ||
}) | ||
assert.NoError(t, err) | ||
assert.Equal(t, "", stdout) | ||
raw, err := os.ReadFile(filepath.Join(td, "manifests.yaml")) | ||
assert.NoError(t, err) | ||
assert.Contains(t, string(raw), "---\napiVersion: apps/v1\nkind: Deployment\n") | ||
}) | ||
} |
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,122 @@ | ||
// Copyright 2024 Humanitec | ||
// | ||
// 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 ( | ||
"context" | ||
"os" | ||
"path/filepath" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/score-spec/score-go/framework" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
|
||
"github.com/score-spec/score-k8s/internal/project" | ||
) | ||
|
||
func TestInitNominal(t *testing.T) { | ||
td := t.TempDir() | ||
|
||
wd, _ := os.Getwd() | ||
require.NoError(t, os.Chdir(td)) | ||
defer func() { | ||
require.NoError(t, os.Chdir(wd)) | ||
}() | ||
|
||
stdout, stderr, err := executeAndResetCommand(context.Background(), rootCmd, []string{"init"}) | ||
assert.NoError(t, err) | ||
assert.Equal(t, "", stdout) | ||
assert.NotEqual(t, "", strings.TrimSpace(stderr)) | ||
|
||
stdout, stderr, err = executeAndResetCommand(context.Background(), rootCmd, []string{"generate", "score.yaml"}) | ||
assert.NoError(t, err) | ||
assert.Equal(t, ``, stdout) | ||
assert.NotEqual(t, "", strings.TrimSpace(stderr)) | ||
|
||
sd, ok, err := project.LoadStateDirectory(".") | ||
assert.NoError(t, err) | ||
if assert.True(t, ok) { | ||
assert.Equal(t, project.DefaultRelativeStateDirectory, sd.Path) | ||
assert.Len(t, sd.State.Workloads, 1) | ||
assert.Equal(t, map[framework.ResourceUid]framework.ScoreResourceState[project.ResourceExtras]{}, sd.State.Resources) | ||
assert.Equal(t, map[string]interface{}{}, sd.State.SharedState) | ||
} | ||
} | ||
|
||
func TestInitNoSample(t *testing.T) { | ||
td := t.TempDir() | ||
|
||
wd, _ := os.Getwd() | ||
require.NoError(t, os.Chdir(td)) | ||
defer func() { | ||
require.NoError(t, os.Chdir(wd)) | ||
}() | ||
|
||
stdout, stderr, err := executeAndResetCommand(context.Background(), rootCmd, []string{"init", "--no-sample"}) | ||
assert.NoError(t, err) | ||
assert.Equal(t, "", stdout) | ||
assert.NotEqual(t, "", strings.TrimSpace(stderr)) | ||
|
||
_, err = os.Stat("score.yaml") | ||
assert.ErrorIs(t, err, os.ErrNotExist) | ||
} | ||
|
||
func TestInitNominal_run_twice(t *testing.T) { | ||
td := t.TempDir() | ||
|
||
wd, _ := os.Getwd() | ||
require.NoError(t, os.Chdir(td)) | ||
defer func() { | ||
require.NoError(t, os.Chdir(wd)) | ||
}() | ||
|
||
// first init | ||
stdout, stderr, err := executeAndResetCommand(context.Background(), rootCmd, []string{"init", "--file", "score2.yaml"}) | ||
assert.NoError(t, err) | ||
assert.Equal(t, "", stdout) | ||
assert.NotEqual(t, "", strings.TrimSpace(stderr)) | ||
|
||
// check default provisioners exists and overwrite it with an empty array | ||
dpf, err := os.Stat(filepath.Join(td, ".score-k8s", "zz-default.provisioners.yaml")) | ||
assert.NoError(t, err) | ||
assert.NoError(t, os.WriteFile(filepath.Join(td, ".score-k8s", dpf.Name()), []byte("[]"), 0644)) | ||
|
||
// init again | ||
stdout, stderr, err = executeAndResetCommand(context.Background(), rootCmd, []string{"init"}) | ||
assert.NoError(t, err) | ||
assert.Equal(t, "", stdout) | ||
assert.NotEqual(t, "", strings.TrimSpace(stderr)) | ||
|
||
// verify that default provisioners was not overwritten again | ||
dpf, err = os.Stat(filepath.Join(td, ".score-k8s", dpf.Name())) | ||
assert.NoError(t, err) | ||
assert.Equal(t, 2, int(dpf.Size())) | ||
|
||
_, err = os.Stat("score.yaml") | ||
assert.NoError(t, err) | ||
_, err = os.Stat("score2.yaml") | ||
assert.NoError(t, err) | ||
|
||
sd, ok, err := project.LoadStateDirectory(".") | ||
assert.NoError(t, err) | ||
if assert.True(t, ok) { | ||
assert.Equal(t, project.DefaultRelativeStateDirectory, sd.Path) | ||
assert.Equal(t, map[string]framework.ScoreWorkloadState[framework.NoExtras]{}, sd.State.Workloads) | ||
assert.Equal(t, map[framework.ResourceUid]framework.ScoreResourceState[project.ResourceExtras]{}, sd.State.Resources) | ||
assert.Equal(t, map[string]interface{}{}, sd.State.SharedState) | ||
} | ||
} |
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,77 @@ | ||
// Copyright 2024 Humanitec | ||
// | ||
// 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" | ||
"context" | ||
"regexp" | ||
"testing" | ||
|
||
"github.com/spf13/cobra" | ||
"github.com/spf13/pflag" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
// executeAndResetCommand is a test helper that runs and then resets a command for executing in another test. | ||
func executeAndResetCommand(ctx context.Context, cmd *cobra.Command, args []string) (string, string, error) { | ||
beforeOut, beforeErr := cmd.OutOrStdout(), cmd.ErrOrStderr() | ||
defer func() { | ||
cmd.SetOut(beforeOut) | ||
cmd.SetErr(beforeErr) | ||
// also have to remove completion commands which get auto added and bound to an output buffer | ||
for _, command := range cmd.Commands() { | ||
if command.Name() == "completion" { | ||
cmd.RemoveCommand(command) | ||
break | ||
} | ||
} | ||
}() | ||
|
||
nowOut, nowErr := new(bytes.Buffer), new(bytes.Buffer) | ||
cmd.SetOut(nowOut) | ||
cmd.SetErr(nowErr) | ||
cmd.SetArgs(args) | ||
subCmd, err := cmd.ExecuteContextC(ctx) | ||
if subCmd != nil { | ||
subCmd.SetOut(nil) | ||
subCmd.SetErr(nil) | ||
subCmd.SetContext(nil) | ||
subCmd.SilenceUsage = false | ||
subCmd.Flags().VisitAll(func(f *pflag.Flag) { | ||
if f.Value.Type() == "stringArray" { | ||
_ = f.Value.(pflag.SliceValue).Replace(nil) | ||
} else { | ||
_ = f.Value.Set(f.DefValue) | ||
} | ||
}) | ||
} | ||
return nowOut.String(), nowErr.String(), err | ||
} | ||
|
||
func TestRootVersion(t *testing.T) { | ||
stdout, stderr, err := executeAndResetCommand(context.Background(), rootCmd, []string{"--version"}) | ||
assert.NoError(t, err) | ||
pattern := regexp.MustCompile(`^score-k8s 0.0.0 \(build: \S+, sha: \S+\)\n$`) | ||
assert.Truef(t, pattern.MatchString(stdout), "%s does not match: '%s'", pattern.String(), stdout) | ||
assert.Equal(t, "", stderr) | ||
} | ||
|
||
func TestRootUnknown(t *testing.T) { | ||
stdout, stderr, err := executeAndResetCommand(context.Background(), rootCmd, []string{"unknown"}) | ||
assert.EqualError(t, err, "unknown command \"unknown\" for \"score-k8s\"") | ||
assert.Equal(t, "", stdout) | ||
assert.Equal(t, "", stderr) | ||
} |