mirror of
https://github.com/coder/coder.git
synced 2026-06-04 05:28:20 +00:00
33b9487899
This change allows proper unmarshaling of `devcontainer.json` and will no longer break EnvInfoer or the Web Terminal. Fixes coder/internal#556
149 lines
3.5 KiB
Go
149 lines
3.5 KiB
Go
package dcspec_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"slices"
|
|
"testing"
|
|
|
|
"github.com/google/go-cmp/cmp"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/coder/coder/v2/agent/agentcontainers/dcspec"
|
|
"github.com/coder/coder/v2/coderd/util/ptr"
|
|
)
|
|
|
|
func TestUnmarshalDevContainer(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
type testCase struct {
|
|
name string
|
|
file string
|
|
wantErr bool
|
|
want dcspec.DevContainer
|
|
}
|
|
tests := []testCase{
|
|
{
|
|
name: "minimal",
|
|
file: filepath.Join("testdata", "minimal.json"),
|
|
want: dcspec.DevContainer{
|
|
Image: ptr.Ref("test-image"),
|
|
},
|
|
},
|
|
{
|
|
name: "arrays",
|
|
file: filepath.Join("testdata", "arrays.json"),
|
|
want: dcspec.DevContainer{
|
|
Image: ptr.Ref("test-image"),
|
|
RunArgs: []string{"--network=host", "--privileged"},
|
|
ForwardPorts: []dcspec.ForwardPort{
|
|
{
|
|
Integer: ptr.Ref[int64](8080),
|
|
},
|
|
{
|
|
String: ptr.Ref("3000:3000"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "devcontainers/template-starter",
|
|
file: filepath.Join("testdata", "devcontainers-template-starter.json"),
|
|
wantErr: false,
|
|
want: dcspec.DevContainer{
|
|
Image: ptr.Ref("mcr.microsoft.com/devcontainers/javascript-node:1-18-bullseye"),
|
|
Features: &dcspec.Features{},
|
|
Customizations: map[string]interface{}{
|
|
"vscode": map[string]interface{}{
|
|
"extensions": []interface{}{
|
|
"mads-hartmann.bash-ide-vscode",
|
|
"dbaeumer.vscode-eslint",
|
|
},
|
|
},
|
|
},
|
|
PostCreateCommand: &dcspec.Command{
|
|
String: ptr.Ref("npm install -g @devcontainers/cli"),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
var missingTests []string
|
|
files, err := filepath.Glob("testdata/*.json")
|
|
require.NoError(t, err, "glob test files failed")
|
|
for _, file := range files {
|
|
if !slices.ContainsFunc(tests, func(tt testCase) bool {
|
|
return tt.file == file
|
|
}) {
|
|
missingTests = append(missingTests, file)
|
|
}
|
|
}
|
|
require.Empty(t, missingTests, "missing tests case for files: %v", missingTests)
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
data, err := os.ReadFile(tt.file)
|
|
require.NoError(t, err, "read test file failed")
|
|
|
|
got, err := dcspec.UnmarshalDevContainer(data)
|
|
if tt.wantErr {
|
|
require.Error(t, err, "want error but got nil")
|
|
return
|
|
}
|
|
require.NoError(t, err, "unmarshal DevContainer failed")
|
|
|
|
// Compare the unmarshaled data with the expected data.
|
|
if diff := cmp.Diff(tt.want, got); diff != "" {
|
|
require.Empty(t, diff, "UnmarshalDevContainer() mismatch (-want +got):\n%s", diff)
|
|
}
|
|
|
|
// Test that marshaling works (without comparing to original).
|
|
marshaled, err := got.Marshal()
|
|
require.NoError(t, err, "marshal DevContainer back to JSON failed")
|
|
require.NotEmpty(t, marshaled, "marshaled JSON should not be empty")
|
|
|
|
// Verify the marshaled JSON can be unmarshaled back.
|
|
var unmarshaled interface{}
|
|
err = json.Unmarshal(marshaled, &unmarshaled)
|
|
require.NoError(t, err, "unmarshal marshaled JSON failed")
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestUnmarshalDevContainer_EdgeCases(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
tests := []struct {
|
|
name string
|
|
json string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "empty JSON",
|
|
json: "{}",
|
|
wantErr: false,
|
|
},
|
|
{
|
|
name: "invalid JSON",
|
|
json: "{not valid json",
|
|
wantErr: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
_, err := dcspec.UnmarshalDevContainer([]byte(tt.json))
|
|
if tt.wantErr {
|
|
require.Error(t, err, "want error but got nil")
|
|
return
|
|
}
|
|
require.NoError(t, err, "unmarshal DevContainer failed")
|
|
})
|
|
}
|
|
}
|