Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

dev_test.gno

4.18 Kb · 158 lines
  1package dev
  2
  3import (
  4	"chain/runtime"
  5	"strconv"
  6	"strings"
  7	"testing"
  8
  9	"gno.land/p/nt/testutils/v0"
 10
 11	ninep "gno.land/p/moul/x/plan9/ninep/v0"
 12
 13	nsrealm "gno.land/r/moul/x/plan9/ns/v0"
 14)
 15
 16func read(t *testing.T, name string) string {
 17	t.Helper()
 18	f, err := tree.Root().Walk(name)
 19	if err != nil {
 20		t.Fatalf("walk %s: %v", name, err)
 21	}
 22	data, err := ninep.ReadAll(f)
 23	if err != nil {
 24		t.Fatalf("read %s: %v", name, err)
 25	}
 26	return data
 27}
 28
 29func TestDevicesFollowTheChain(t *testing.T) {
 30	if got, want := read(t, "sysname"), runtime.ChainID(); got != want {
 31		t.Errorf("sysname: got %q, want %q", got, want)
 32	}
 33	if got, want := read(t, "domain"), runtime.ChainDomain(); got != want {
 34		t.Errorf("domain: got %q, want %q", got, want)
 35	}
 36	if got, want := read(t, "height"), strconv.FormatInt(runtime.ChainHeight(), 10); got != want {
 37		t.Errorf("height: got %q, want %q", got, want)
 38	}
 39
 40	// A device is code, not storage: advance the chain and the file follows.
 41	before := read(t, "height")
 42	testing.SkipHeights(5)
 43	after := read(t, "height")
 44	if before == after {
 45		t.Errorf("height did not move: %q", after)
 46	}
 47	b, _ := strconv.ParseInt(before, 10, 64)
 48	a, _ := strconv.ParseInt(after, 10, 64)
 49	if a-b != 5 {
 50		t.Errorf("height moved by %d, want 5", a-b)
 51	}
 52}
 53
 54func TestRandomIsBlockDeterministic(t *testing.T) {
 55	a := read(t, "random")
 56	if len(a) != 64 {
 57		t.Errorf("a sha256 in hex is 64 characters, got %d", len(a))
 58	}
 59	if a != read(t, "random") {
 60		t.Error("two reads in the same block must agree, or Render is a consensus bug")
 61	}
 62	testing.SkipHeights(1)
 63	if a == read(t, "random") {
 64		t.Error("the value should change with the block")
 65	}
 66}
 67
 68func TestNullAndZero(t *testing.T) {
 69	if got := read(t, "null"); got != "" {
 70		t.Errorf("null: %q", got)
 71	}
 72	f, _ := tree.Root().Walk("zero")
 73	got, _ := f.Read(0, 4)
 74	if got != "\x00\x00\x00\x00" {
 75		t.Errorf("zero: %q", got)
 76	}
 77	// An endless file must not answer an unbounded read with an endless value.
 78	if got, _ := f.Read(0, -1); got != "" {
 79		t.Errorf("unbounded read of /dev/zero: %d bytes", len(got))
 80	}
 81	if got, _ := f.Read(0, 1<<20); len(got) != 4096 {
 82		t.Errorf("a huge read should cap at 4096, got %d", len(got))
 83	}
 84}
 85
 86func TestSessionReportsAPlainKey(t *testing.T) {
 87	got := read(t, "session")
 88	if got != "session no\nscope full\n" {
 89		t.Errorf("a plain key has no session scope: %q", got)
 90	}
 91}
 92
 93func TestDriversListsEveryDevice(t *testing.T) {
 94	got := read(t, "drivers")
 95	ents, err := tree.Root().ReadDir()
 96	if err != nil {
 97		t.Fatalf("readdir: %v", err)
 98	}
 99	for _, e := range ents {
100		if !strings.Contains(got, e.Name+"\t") {
101			t.Errorf("/dev/drivers does not document %q", e.Name)
102		}
103	}
104	if len(ents) != len(docs) {
105		t.Errorf("%d devices but %d documented", len(ents), len(docs))
106	}
107}
108
109func TestTreeIsReadOnly(t *testing.T) {
110	var f ninep.File = tree.Root()
111	if _, ok := f.(ninep.Mutable); ok {
112		t.Error("a device tree handed to other realms must not be Mutable")
113	}
114}
115
116// TestPostedAtDeployTime is the cross-realm claim the whole suite rests on:
117// this realm pushed an interface value into another realm at init, and that
118// realm can call it back later from a read.
119func TestPostedAtDeployTime(t *testing.T) {
120	found := false
121	for _, s := range nsrealm.Services() {
122		if s == "dev" {
123			found = true
124		}
125	}
126	if !found {
127		t.Fatalf("dev is not posted in /srv: %v", nsrealm.Services())
128	}
129}
130
131func TestAFreshNamespaceHasDevBound(cur realm, t *testing.T) {
132	user := testutils.TestAddress("glenda")
133	testing.SetRealm(testing.NewUserRealm(user))
134	nsrealm.Reset(cross(cur))
135	// Touch the namespace so it is built with /dev already bound.
136	nsrealm.Exec(cross(cur), "echo hi > /tmp/hi")
137
138	out, err := nsrealm.Run(user.String(), "ls /dev")
139	if err != nil {
140		t.Fatalf("ls /dev: %v", err)
141	}
142	for _, d := range docs {
143		if !strings.Contains(out, d[0]) {
144			t.Errorf("ls /dev is missing %q: %q", d[0], out)
145		}
146	}
147	got, err := nsrealm.Run(user.String(), "cat /dev/sysname")
148	if err != nil {
149		t.Fatalf("cat: %v", err)
150	}
151	if got != runtime.ChainID() {
152		t.Errorf("reading this realm's device through another realm's namespace: %q", got)
153	}
154	// And the mount table says where it came from.
155	if ns := nsrealm.Namespace(user.String()); !strings.Contains(ns, "bind /srv/dev /dev") {
156		t.Errorf("mount table: %q", ns)
157	}
158}