package nix_test import ( "context" "errors" "os" "os/exec" "reflect" "slices" "syscall" "testing" "unsafe" "gensokyo.uk/nix" ) func TestContext(t *testing.T) { ctx := nix.New(t.Context(), &nix.BinaryCache{ Compression: "none", ParallelCompression: false, Bucket: "example", Endpoint: "s3.example.org", Region: "us-east-1", Scheme: "http", CredentialsPath: "/dev/null", KeyPath: nonexistent, }, []string{ nix.FlagOption, nix.OptionBuildUseSubstitutes, nix.ValueFalse, nix.FlagOption, nix.OptionSubstituters, "", nix.FlagOption, nix.OptionTrustedSubstituters, "", nix.FlagOption, nix.OptionTrustedPublicKeys, "", }, nil, nil) extraVal := reflect.ValueOf(ctx).Elem().FieldByName("extra") wantExtra := reflect.NewAt(extraVal.Type(), unsafe.Pointer(extraVal.UnsafeAddr())).Elem().Interface().([]string) t.Run("extra", func(t *testing.T) { got := ctx.Extra() if !slices.Equal(got, wantExtra) { t.Errorf("Extra: %#v, want %#v", got, wantExtra) } got[0] = "\x00" if slices.Equal(got, wantExtra) { t.Errorf("Extra did not return a copy") } }) t.Run("store env", func(t *testing.T) { t.Run("nil", func(t *testing.T) { want := nix.New(t.Context(), nil, nil, nil, nil).StoreEnv() if want != nil { t.Errorf("StoreEnv: %#v", want) } }) want := []string{"AWS_SHARED_CREDENTIALS_FILE=/dev/null"} got := ctx.StoreEnv() if !slices.Equal(got, want) { t.Errorf("StoreEnv: %#v, want %#v", got, want) } }) } func TestNixWriteStdin(t *testing.T) { t.Run("store", func(t *testing.T) { ctx := nix.New(t.Context(), &nix.BinaryCache{ Compression: "none", ParallelCompression: false, Bucket: "example", Endpoint: "s3.example.org", Region: "us-east-1", Scheme: "http", CredentialsPath: "/dev/null", KeyPath: nonexistent, }, nil, nil, nil) cmd := ctx.Nix(t.Context(), nix.FlagVersion).(nix.ExecCmd) wantArgs := []string{ nix.Nix, nix.FlagStore, "s3://example?compression=none¶llel-compression=false®ion=us-east-1&scheme=http&endpoint=s3.example.org&secret-key=/proc/nonexistent", nix.FlagVersion} if !slices.Equal(cmd.Args, wantArgs) { t.Errorf("Args = %#v, want %#v", cmd.Args, wantArgs) } wantEnv := []string{nix.EnvAwsSharedCredentialsFile + "=/dev/null"} if !slices.Equal(cmd.Env, wantEnv) { t.Errorf("Env = %#v, want %#v", cmd.Env, wantEnv) } }) t.Run("already set", func(t *testing.T) { ctx := nix.New(t.Context(), nil, nil, os.Stdout, os.Stderr) cmd := nix.ExecCmd{Cmd: exec.CommandContext(t.Context(), nonexistent)} cmd.Stdin(os.Stdin) if _, err := ctx.WriteStdin(cmd, nil, nil); err == nil { t.Fatal("WriteStdinCommand unexpectedly succeeded") } }) t.Run("f returns error", func(t *testing.T) { stubNixCommand(t) ctx := newStubContext(t.Context(), nil, os.Stdout, os.Stderr) cmd := ctx.Nix(t.Context(), "true") if _, err := ctx.WriteStdin( cmd, slices.Values(make([]string, 0)), func() error { return syscall.ENOSYS }, ); !errors.Is(err, syscall.ENOSYS) { t.Fatalf("WriteStdinCommand: error = %v, want %v", err, syscall.ENOSYS) } }) t.Run("exit before cancel", func(t *testing.T) { stubNixCommand(t) ctx := newStubContext(t.Context(), nil, os.Stdout, os.Stderr) c, cancel := context.WithCancel(t.Context()) defer cancel() cmd := ctx.Nix(c, "true").(nix.ExecCmd) if err := cmd.Start(); err != nil { t.Fatalf("Start: error = %v", err) } // Cancel is skipped after exec.Cmd.Wait completes if _, err := cmd.Process.Wait(); err != nil { t.Fatalf("Wait: error = %v", err) } cancel() if cmd.Err != nil { t.Fatalf("Err = %v", cmd.Err) } }) }