nixbuild/instantiated_test.go
Ophestra 4d9d4bcef2
exec: append custom store
This is primarily for chroot stores. This might not be useful however since chroot store breaks builds.
2025-07-23 12:09:32 +09:00

197 lines
5.3 KiB
Go

package nix_test
import (
"errors"
"io"
"os"
"os/exec"
"slices"
"strings"
"testing"
"gensokyo.uk/nix"
)
func TestInstantiated(t *testing.T) {
stubNixCommand(t)
testCases := []struct {
name string
want []string
wantErr error
}{
{"bad fields", nil, &nix.MalformedInstantiatedError{Type: nix.InstantiatedBadFields}},
{"unexpected quotes left", nil, &nix.MalformedInstantiatedError{Type: nix.InstantiatedUnexpectedQuotes}},
{"unexpected quotes right", nil, &nix.MalformedInstantiatedError{Type: nix.InstantiatedUnexpectedQuotes}},
{"unexpected quotes short", nil, &nix.MalformedInstantiatedError{Type: nix.InstantiatedUnexpectedQuotes}},
{"not absolute", nil, &nix.MalformedInstantiatedError{Type: nix.InstantiatedNotAbsolute}},
{"good segment", segmentWant, nil},
{"getchoo atlas", getchooAtlasInstantiated, nil},
{"getchoo glados", getchooGladosInstantiated, nil},
{"pluiedev pappardelle", pluiedevPappardelleInstantiated, nil},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
var stderr io.Writer
if tc.wantErr != nil {
stderr = os.Stderr
}
sample := instSample[tc.name]
t.Run("decoder", func(t *testing.T) {
out := strings.NewReader(sample)
decoder := nix.NewInstantiatedDecoder(out, stderr)
got, err := decoder.Decode()
if !errors.Is(err, tc.wantErr) {
t.Fatalf("Decode: error = %v, want %v", err, tc.wantErr)
}
if tc.wantErr != nil {
t.Logf("Decode: error = %v", err)
t.Run("scan after error", func(t *testing.T) {
if decoder.Scan() {
t.Fatalf("Scan unexpectedly succeeded on faulted decoder")
}
})
return
}
if !slices.Equal(got, tc.want) {
t.Errorf("Decode: %#v, want %#v", got, tc.want)
}
})
t.Run("evaluator", func(t *testing.T) {
ctx := newStubContext(t.Context(), nil, os.Stdout, stderr)
got, err := nix.EvalInstantiated(ctx, tc.name)
if !errors.Is(err, tc.wantErr) {
t.Fatalf("EvalInstantiated: error = %v, want %v", err, tc.wantErr)
}
if tc.wantErr != nil {
t.Logf("EvalInstantiated: error = %v", err)
return
}
if !slices.Equal(got, tc.want) {
t.Errorf("EvalInstantiated: %#v, want %#v", got, tc.want)
}
})
})
}
}
func stubInstantiatedEvaluator(args []string) error {
_, _ = os.Stderr.Write([]byte(instSample[args[0]]))
return nil
}
func TestInstantiatedDecoderStopEarly(t *testing.T) {
decoder := nix.NewInstantiatedDecoder(strings.NewReader(segmentPrefix+segmentBody+segmentSuffix), os.Stderr)
counter := 3
got := make([]string, 0, counter)
for drv := range decoder.Instantiated() {
got = append(got, drv)
counter--
if counter == 0 {
break
}
}
if !slices.Equal(got, segmentEarly) {
t.Errorf("Instantiated: %#v, want %#v", got, segmentEarly)
}
}
func TestInstantiatedEvaluatorBadCommand(t *testing.T) {
wantErr := os.ErrNotExist
breakNixCommand(t)
if _, err := nix.EvalInstantiated(
nix.New(t.Context(), nil, nil, os.Stdout, os.Stderr),
"",
); !errors.Is(err, wantErr) {
t.Errorf("EvalInstantiated: error = %v, want %v", err, wantErr)
}
}
func TestInstantiatedEvaluatorAlreadySet(t *testing.T) {
stubNixCommand(t)
if _, err := nix.EvalInstantiated(
newStubContextCommand(func(cmd *exec.Cmd) { cmd.Stderr = os.Stderr }, t.Context(), nil, os.Stdout, os.Stderr),
"",
); err == nil {
t.Errorf("EvalInstantiated unexpectedly succeeded")
}
}
func TestMalformedInstantiatedError(t *testing.T) {
t.Run("bad type", func(t *testing.T) {
badErr := errors.New("")
if errors.Is(new(nix.MalformedInstantiatedError), badErr) {
t.Error("unexpected MalformedInstantiatedError equivalence")
}
})
t.Run("nil", func(t *testing.T) {
if errors.Is(new(nix.MalformedInstantiatedError), (*nix.MalformedInstantiatedError)(nil)) {
t.Error("unexpected MalformedInstantiatedError equivalence")
}
})
t.Run("unreachable", func(t *testing.T) {
defer func() {
wantPanic := "unreachable"
if r := recover(); r != wantPanic {
t.Errorf("Error: panic = %q, want %q", r, wantPanic)
}
}()
_ = (&nix.MalformedInstantiatedError{Type: -1}).Error()
})
}
func benchmarkInstantiatedDecoder(b *testing.B, out string) {
decoder := nix.NewInstantiatedDecoder(strings.NewReader(out), nil)
for b.Loop() {
retry:
if !decoder.Scan() {
b.StopTimer()
if err := decoder.Err(); err != nil {
b.Fatalf("Decode: error = %v", err)
}
decoder = nix.NewInstantiatedDecoder(strings.NewReader(out), nil)
b.StartTimer()
goto retry
}
b.StopTimer()
if !strings.HasPrefix(decoder.Text(), "/nix/store") {
b.Fatalf("Text: unexpected prefix: %s", decoder.Text())
}
b.StartTimer()
}
}
func BenchmarkInstantiatedDecoder(b *testing.B) {
benchmarkInstantiatedDecoder(b, pluiedevPappardelleOut)
}
func benchmarkInstantiated(b *testing.B, out string, want []string) {
for b.Loop() {
v, _ := nix.NewInstantiatedDecoder(strings.NewReader(out), nil).Decode()
b.StopTimer()
if !slices.Equal(v, want) {
b.Fatalf("Decode: %#v, want %#v", v, want)
}
b.StartTimer()
}
}
func BenchmarkInstantiated(b *testing.B) {
/* 27750 raw, 10729 deduplicated */
benchmarkInstantiated(b, getchooGladosOut, getchooGladosInstantiated)
}
func BenchmarkInstantiatedCopy(b *testing.B) {
/* 40177 raw, 10685 deduplicated */
benchmarkInstantiated(b, pluiedevPappardelleOut, pluiedevPappardelleInstantiated)
}