Files
kustomize/kyaml/openapi/internal/embeddedasset/asset_test.go
koba1t 9216c6f573 chore: refactor read scheme to openapi from kubernetes api definition
Previously, only a single embedded Kubernetes API version could be specified, resulting in a lack of support for certain GVKs.
To address this, the goal is to create and utilize a unified scheme that consolidates Kubernetes API definitions.
As a preliminary step, the current method of loading API definitions will be improved.
2026-08-02 22:39:33 +09:00

203 lines
5.8 KiB
Go

// Copyright 2026 The Kubernetes Authors.
// SPDX-License-Identifier: Apache-2.0
package embeddedasset
import (
"bytes"
"compress/gzip"
"os"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/require"
)
const testAssetPath = "root/nested/asset.txt"
var testModTime = time.Unix(1700000000, 0) //nolint:gochecknoglobals
func TestAsset(t *testing.T) {
contents := []byte("asset contents")
for name, compressed := range map[string]bool{
"raw": false,
"compressed": true,
} {
t.Run(name, func(t *testing.T) {
data := contents
if compressed {
data = gzipData(t, contents)
}
file := newTestFile(data, int64(len(contents)), compressed)
got, err := Asset(file, testAssetPath)
require.NoError(t, err)
require.Equal(t, contents, got)
got[0] ^= 0xff
again, err := Asset(file, "root\\nested\\asset.txt")
require.NoError(t, err)
require.Equal(t, contents, again, "Asset must return a fresh byte slice")
})
}
_, err := Asset(newTestFile(nil, 0, false), "missing")
require.ErrorContains(t, err, "Asset missing not found")
}
func TestAssetRejectsInvalidCompressedData(t *testing.T) {
t.Run("invalid gzip", func(t *testing.T) {
file := newTestFile([]byte("not gzip"), 1, true)
_, err := Asset(file, testAssetPath)
require.ErrorContains(t, err, "read \"root/nested/asset.txt\"")
})
t.Run("invalid gzip body", func(t *testing.T) {
data := gzipData(t, []byte("asset contents"))
data[len(data)-1] ^= 0xff
file := newTestFile(data, int64(len("asset contents")), true)
_, err := Asset(file, testAssetPath)
require.ErrorContains(t, err, "read \"root/nested/asset.txt\"")
})
t.Run("declared size too small", func(t *testing.T) {
contents := []byte("asset contents")
file := newTestFile(gzipData(t, contents), int64(len(contents)-1), true)
_, err := Asset(file, testAssetPath)
require.ErrorContains(t, err, "expected 13 bytes, got 14")
})
t.Run("declared size too large", func(t *testing.T) {
contents := []byte("asset contents")
file := newTestFile(gzipData(t, contents), int64(len(contents)+1), true)
_, err := Asset(file, testAssetPath)
require.ErrorContains(t, err, "expected 15 bytes, got 14")
})
}
func TestMustAsset(t *testing.T) {
contents := []byte("asset contents")
file := newTestFile(contents, int64(len(contents)), false)
require.Equal(t, contents, MustAsset(file, testAssetPath))
require.Panics(t, func() {
MustAsset(file, "missing")
})
}
func TestAssetInfo(t *testing.T) {
contents := []byte("asset contents")
file := newTestFile(contents, int64(len(contents)), false)
info, err := AssetInfo(file, "root\\nested\\asset.txt")
require.NoError(t, err)
require.Equal(t, "asset.txt", info.Name())
require.Equal(t, int64(len(contents)), info.Size())
require.Equal(t, os.FileMode(0o640), info.Mode())
require.Equal(t, testModTime, info.ModTime())
require.False(t, info.IsDir())
require.Nil(t, info.Sys())
_, err = AssetInfo(file, "missing")
require.ErrorContains(t, err, "AssetInfo missing not found")
}
func TestAssetDir(t *testing.T) {
file := newTestFile(nil, 0, false)
tests := []struct {
name string
path string
expected []string
wantErr bool
}{
{name: "root", path: "", expected: []string{"root"}},
{name: "first level", path: "root", expected: []string{"nested"}},
{name: "nested", path: "root/nested", expected: []string{"asset.txt"}},
{name: "backslashes", path: "root\\nested", expected: []string{"asset.txt"}},
{name: "file", path: testAssetPath, wantErr: true},
{name: "missing", path: "missing", wantErr: true},
{name: "trailing slash", path: "root/nested/", wantErr: true},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
children, err := AssetDir(file, test.path)
if test.wantErr {
require.Error(t, err)
return
}
require.NoError(t, err)
require.Equal(t, test.expected, children)
})
}
}
func TestRestoreAsset(t *testing.T) {
contents := []byte("asset contents")
file := newTestFile(contents, int64(len(contents)), false)
dir := t.TempDir()
require.NoError(t, RestoreAsset(file, dir, "root\\nested\\asset.txt"))
restored, err := os.ReadFile(filepath.Join(dir, "root", "nested", "asset.txt"))
require.NoError(t, err)
require.Equal(t, contents, restored)
require.Error(t, RestoreAsset(file, dir, "missing"))
}
func TestRestoreAssets(t *testing.T) {
contents := []byte("asset contents")
file := newTestFile(contents, int64(len(contents)), false)
for _, name := range []string{"", "root", testAssetPath} {
t.Run(name, func(t *testing.T) {
dir := t.TempDir()
require.NoError(t, RestoreAssets(file, dir, name))
restored, err := os.ReadFile(filepath.Join(dir, "root", "nested", "asset.txt"))
require.NoError(t, err)
require.Equal(t, contents, restored)
})
}
require.Error(t, RestoreAssets(file, t.TempDir(), "missing"))
}
func TestCanonical(t *testing.T) {
tests := map[string]string{
"": "",
"root/nested/asset.txt": "root/nested/asset.txt",
"root\\nested\\asset.txt": "root/nested/asset.txt",
"root/nested\\asset.txt": "root/nested/asset.txt",
}
for input, expected := range tests {
require.Equal(t, expected, canonical(input))
}
}
func TestFilePath(t *testing.T) {
dir := t.TempDir()
expected := filepath.Join(dir, "root", "nested", "asset.txt")
require.Equal(t, expected, filePath(dir, "root/nested/asset.txt"))
require.Equal(t, expected, filePath(dir, "root\\nested\\asset.txt"))
}
func newTestFile(data []byte, size int64, compressed bool) File {
return File{
Path: testAssetPath,
Data: data,
Compressed: compressed,
Size: size,
Mode: 0o640,
ModTime: testModTime,
}
}
func gzipData(t *testing.T, data []byte) []byte {
t.Helper()
var buffer bytes.Buffer
writer := gzip.NewWriter(&buffer)
_, err := writer.Write(data)
require.NoError(t, err)
require.NoError(t, writer.Close())
return buffer.Bytes()
}