system/mkdir: use syscall dispatcher
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Test / Create distribution (push) Successful in 32s
				
			
		
			
				
	
				Test / Sandbox (push) Successful in 2m7s
				
			
		
			
				
	
				Test / Hakurei (push) Successful in 3m8s
				
			
		
			
				
	
				Test / Hpkg (push) Successful in 3m55s
				
			
		
			
				
	
				Test / Sandbox (race detector) (push) Successful in 4m29s
				
			
		
			
				
	
				Test / Hakurei (race detector) (push) Successful in 5m4s
				
			
		
			
				
	
				Test / Flake checks (push) Successful in 1m25s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Test / Create distribution (push) Successful in 32s
				
			Test / Sandbox (push) Successful in 2m7s
				
			Test / Hakurei (push) Successful in 3m8s
				
			Test / Hpkg (push) Successful in 3m55s
				
			Test / Sandbox (race detector) (push) Successful in 4m29s
				
			Test / Hakurei (race detector) (push) Successful in 5m4s
				
			Test / Flake checks (push) Successful in 1m25s
				
			This enables mkdir op methods to be instrumented. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
		
							parent
							
								
									6cc2b406a4
								
							
						
					
					
						commit
						323d132c40
					
				| @ -15,6 +15,10 @@ type syscallDispatcher interface { | |||||||
| 	// just synchronising access is not enough, as this is for test instrumentation. | 	// just synchronising access is not enough, as this is for test instrumentation. | ||||||
| 	new(f func(k syscallDispatcher)) | 	new(f func(k syscallDispatcher)) | ||||||
| 
 | 
 | ||||||
|  | 	// mkdir provides os.Mkdir. | ||||||
|  | 	mkdir(name string, perm os.FileMode) error | ||||||
|  | 	// chmod provides os.Chmod. | ||||||
|  | 	chmod(name string, mode os.FileMode) error | ||||||
| 	// link provides os.Link. | 	// link provides os.Link. | ||||||
| 	link(oldname, newname string) error | 	link(oldname, newname string) error | ||||||
| 	// remove provides os.Remove. | 	// remove provides os.Remove. | ||||||
| @ -44,6 +48,8 @@ type direct struct{} | |||||||
| 
 | 
 | ||||||
| func (k direct) new(f func(k syscallDispatcher)) { go f(k) } | func (k direct) new(f func(k syscallDispatcher)) { go f(k) } | ||||||
| 
 | 
 | ||||||
|  | func (k direct) mkdir(name string, perm os.FileMode) error { return os.Mkdir(name, perm) } | ||||||
|  | func (k direct) chmod(name string, mode os.FileMode) error { return os.Chmod(name, mode) } | ||||||
| func (k direct) link(oldname, newname string) error        { return os.Link(oldname, newname) } | func (k direct) link(oldname, newname string) error        { return os.Link(oldname, newname) } | ||||||
| func (k direct) remove(name string) error                  { return os.Remove(name) } | func (k direct) remove(name string) error                  { return os.Remove(name) } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -192,6 +192,20 @@ type kstub struct{ *stub.Stub[syscallDispatcher] } | |||||||
| 
 | 
 | ||||||
| func (k *kstub) new(f func(k syscallDispatcher)) { k.Helper(); k.New(f) } | func (k *kstub) new(f func(k syscallDispatcher)) { k.Helper(); k.New(f) } | ||||||
| 
 | 
 | ||||||
|  | func (k *kstub) mkdir(name string, perm os.FileMode) error { | ||||||
|  | 	k.Helper() | ||||||
|  | 	return k.Expects("mkdir").Error( | ||||||
|  | 		stub.CheckArg(k.Stub, "name", name, 0), | ||||||
|  | 		stub.CheckArg(k.Stub, "perm", perm, 1)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (k *kstub) chmod(name string, mode os.FileMode) error { | ||||||
|  | 	k.Helper() | ||||||
|  | 	return k.Expects("chmod").Error( | ||||||
|  | 		stub.CheckArg(k.Stub, "name", name, 0), | ||||||
|  | 		stub.CheckArg(k.Stub, "mode", mode, 1)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func (k *kstub) link(oldname, newname string) error { | func (k *kstub) link(oldname, newname string) error { | ||||||
| 	k.Helper() | 	k.Helper() | ||||||
| 	return k.Expects("link").Error( | 	return k.Expects("link").Error( | ||||||
|  | |||||||
| @ -28,32 +28,31 @@ type mkdirOp struct { | |||||||
| 
 | 
 | ||||||
| func (m *mkdirOp) Type() Enablement { return m.et } | func (m *mkdirOp) Type() Enablement { return m.et } | ||||||
| 
 | 
 | ||||||
| func (m *mkdirOp) apply(*I) error { | func (m *mkdirOp) apply(sys *I) error { | ||||||
| 	msg.Verbose("ensuring directory", m) | 	sys.verbose("ensuring directory", m) | ||||||
| 
 | 
 | ||||||
| 	// create directory | 	if err := sys.mkdir(m.path, m.perm); err != nil { | ||||||
| 	if err := os.Mkdir(m.path, m.perm); err != nil { |  | ||||||
| 		if !errors.Is(err, os.ErrExist) { | 		if !errors.Is(err, os.ErrExist) { | ||||||
| 			return newOpError("mkdir", err, false) | 			return newOpError("mkdir", err, false) | ||||||
| 		} | 		} | ||||||
| 		// directory exists, ensure mode | 		// directory exists, ensure mode | ||||||
| 		return newOpError("mkdir", os.Chmod(m.path, m.perm), false) | 		return newOpError("mkdir", sys.chmod(m.path, m.perm), false) | ||||||
| 	} else { | 	} else { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (m *mkdirOp) revert(_ *I, ec *Criteria) error { | func (m *mkdirOp) revert(sys *I, ec *Criteria) error { | ||||||
| 	if !m.ephemeral { | 	if !m.ephemeral { | ||||||
| 		// skip non-ephemeral dir and do not log anything | 		// skip non-ephemeral dir and do not log anything | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if ec.hasType(m.Type()) { | 	if ec.hasType(m.Type()) { | ||||||
| 		msg.Verbose("destroying ephemeral directory", m) | 		sys.verbose("destroying ephemeral directory", m) | ||||||
| 		return newOpError("mkdir", os.Remove(m.path), true) | 		return newOpError("mkdir", sys.remove(m.path), true) | ||||||
| 	} else { | 	} else { | ||||||
| 		msg.Verbose("skipping ephemeral directory", m) | 		sys.verbose("skipping ephemeral directory", m) | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | |||||||
| @ -4,72 +4,108 @@ import ( | |||||||
| 	"os" | 	"os" | ||||||
| 	"testing" | 	"testing" | ||||||
| 
 | 
 | ||||||
| 	"hakurei.app/container" | 	"hakurei.app/container/stub" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func TestEnsure(t *testing.T) { | func TestMkdirOp(t *testing.T) { | ||||||
| 	testCases := []struct { | 	checkOpBehaviour(t, []opBehaviourTestCase{ | ||||||
| 		name string | 		{"mkdir", 0xdeadbeef, 0xff, &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, false}, []stub.Call{ | ||||||
| 		perm os.FileMode | 			call("verbose", stub.ExpectArgs{[]any{"ensuring directory", &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, false}}}, nil, nil), | ||||||
| 	}{ | 			call("mkdir", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, stub.UniqueError(2)), | ||||||
| 		{"/tmp/hakurei.1971", 0701}, | 		}, &OpError{Op: "mkdir", Err: stub.UniqueError(2)}, nil, nil}, | ||||||
| 		{"/tmp/hakurei.1971/tmpdir", 0700}, | 
 | ||||||
| 		{"/tmp/hakurei.1971/tmpdir/150", 0700}, | 		{"chmod", 0xdeadbeef, 0xff, &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, false}, []stub.Call{ | ||||||
| 		{"/run/user/1971/hakurei", 0700}, | 			call("verbose", stub.ExpectArgs{[]any{"ensuring directory", &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, false}}}, nil, nil), | ||||||
| 	} | 			call("mkdir", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, os.ErrExist), | ||||||
| 	for _, tc := range testCases { | 			call("chmod", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, stub.UniqueError(1)), | ||||||
| 		t.Run(tc.name+"_"+tc.perm.String(), func(t *testing.T) { | 		}, &OpError{Op: "mkdir", Err: stub.UniqueError(1)}, nil, nil}, | ||||||
| 			sys := New(t.Context(), 150) | 
 | ||||||
| 			sys.Ensure(tc.name, tc.perm) | 		{"remove", 0xdeadbeef, 0xff, &mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}, []stub.Call{ | ||||||
| 			(&tcOp{User, tc.name}).test(t, sys.ops, []Op{&mkdirOp{User, tc.name, tc.perm, false}}, "Ensure") | 			call("verbose", stub.ExpectArgs{[]any{"ensuring directory", &mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}}}, nil, nil), | ||||||
|  | 			call("mkdir", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, nil), | ||||||
|  | 		}, nil, []stub.Call{ | ||||||
|  | 			call("verbose", stub.ExpectArgs{[]any{"destroying ephemeral directory", &mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}}}, nil, nil), | ||||||
|  | 			call("remove", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9"}, nil, stub.UniqueError(0)), | ||||||
|  | 		}, &OpError{Op: "mkdir", Err: stub.UniqueError(0), Revert: true}}, | ||||||
|  | 
 | ||||||
|  | 		{"success exist chmod", 0xdeadbeef, 0xff, &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, false}, []stub.Call{ | ||||||
|  | 			call("verbose", stub.ExpectArgs{[]any{"ensuring directory", &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, false}}}, nil, nil), | ||||||
|  | 			call("mkdir", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, os.ErrExist), | ||||||
|  | 			call("chmod", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, nil), | ||||||
|  | 		}, nil, nil, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"success ensure", 0xdeadbeef, 0xff, &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, false}, []stub.Call{ | ||||||
|  | 			call("verbose", stub.ExpectArgs{[]any{"ensuring directory", &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, false}}}, nil, nil), | ||||||
|  | 			call("mkdir", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, nil), | ||||||
|  | 		}, nil, nil, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"success skip", 0xdeadbeef, 0xff, &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}, []stub.Call{ | ||||||
|  | 			call("verbose", stub.ExpectArgs{[]any{"ensuring directory", &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}}}, nil, nil), | ||||||
|  | 			call("mkdir", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, nil), | ||||||
|  | 		}, nil, []stub.Call{ | ||||||
|  | 			call("verbose", stub.ExpectArgs{[]any{"skipping ephemeral directory", &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}}}, nil, nil), | ||||||
|  | 		}, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"success", 0xdeadbeef, 0xff, &mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}, []stub.Call{ | ||||||
|  | 			call("verbose", stub.ExpectArgs{[]any{"ensuring directory", &mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}}}, nil, nil), | ||||||
|  | 			call("mkdir", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", os.FileMode(0711)}, nil, nil), | ||||||
|  | 		}, nil, []stub.Call{ | ||||||
|  | 			call("verbose", stub.ExpectArgs{[]any{"destroying ephemeral directory", &mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}}}, nil, nil), | ||||||
|  | 			call("remove", stub.ExpectArgs{"/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9"}, nil, nil), | ||||||
|  | 		}, nil}, | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	checkOpsBuilder(t, "EnsureEphemeral", []opsBuilderTestCase{ | ||||||
|  | 		{"ensure", 0xcafebabe, func(_ *testing.T, sys *I) { | ||||||
|  | 			sys.Ensure("/tmp/hakurei.0", 0700) | ||||||
|  | 		}, []Op{ | ||||||
|  | 			&mkdirOp{User, "/tmp/hakurei.0", 0700, false}, | ||||||
|  | 		}, stub.Expect{}}, | ||||||
|  | 
 | ||||||
|  | 		{"ephemeral", 0xcafebabe, func(_ *testing.T, sys *I) { | ||||||
|  | 			sys.Ephemeral(Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711) | ||||||
|  | 		}, []Op{ | ||||||
|  | 			&mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711, true}, | ||||||
|  | 		}, stub.Expect{}}, | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	checkOpIs(t, []opIsTestCase{ | ||||||
|  | 		{"nil", (*mkdirOp)(nil), (*mkdirOp)(nil), false}, | ||||||
|  | 		{"zero", new(mkdirOp), new(mkdirOp), true}, | ||||||
|  | 
 | ||||||
|  | 		{"ephemeral differs", | ||||||
|  | 			&mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, false}, | ||||||
|  | 			&mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true}, | ||||||
|  | 			false}, | ||||||
|  | 
 | ||||||
|  | 		{"perm differs", | ||||||
|  | 			&mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0701, true}, | ||||||
|  | 			&mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true}, | ||||||
|  | 			false}, | ||||||
|  | 
 | ||||||
|  | 		{"path differs", | ||||||
|  | 			&mkdirOp{Process, "/tmp/hakurei.1/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true}, | ||||||
|  | 			&mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true}, | ||||||
|  | 			false}, | ||||||
|  | 
 | ||||||
|  | 		{"et differs", | ||||||
|  | 			&mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true}, | ||||||
|  | 			&mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true}, | ||||||
|  | 			false}, | ||||||
|  | 
 | ||||||
|  | 		{"equals", | ||||||
|  | 			&mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true}, | ||||||
|  | 			&mkdirOp{Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true}, | ||||||
|  | 			true}, | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	checkOpMeta(t, []opMetaTestCase{ | ||||||
|  | 		{"ensure", &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, false}, | ||||||
|  | 			User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", | ||||||
|  | 			`mode: -rwx------ type: ensure path: "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9"`}, | ||||||
|  | 
 | ||||||
|  | 		{"ephemeral", &mkdirOp{User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0700, true}, | ||||||
|  | 			User, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", | ||||||
|  | 			`mode: -rwx------ type: user path: "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9"`}, | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestEphemeral(t *testing.T) { |  | ||||||
| 	testCases := []struct { |  | ||||||
| 		perm os.FileMode |  | ||||||
| 		tcOp |  | ||||||
| 	}{ |  | ||||||
| 		{0700, tcOp{Process, "/run/user/1971/hakurei/ec07546a772a07cde87389afc84ffd13"}}, |  | ||||||
| 		{0701, tcOp{Process, "/tmp/hakurei.1971/ec07546a772a07cde87389afc84ffd13"}}, |  | ||||||
| 	} |  | ||||||
| 	for _, tc := range testCases { |  | ||||||
| 		t.Run(tc.path+"_"+tc.perm.String()+"_"+TypeString(tc.et), func(t *testing.T) { |  | ||||||
| 			sys := New(t.Context(), 150) |  | ||||||
| 			sys.Ephemeral(tc.et, tc.path, tc.perm) |  | ||||||
| 			tc.test(t, sys.ops, []Op{&mkdirOp{tc.et, tc.path, tc.perm, true}}, "Ephemeral") |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestMkdirString(t *testing.T) { |  | ||||||
| 	testCases := []struct { |  | ||||||
| 		want      string |  | ||||||
| 		ephemeral bool |  | ||||||
| 		et        Enablement |  | ||||||
| 	}{ |  | ||||||
| 		{"ensure", false, User}, |  | ||||||
| 		{"ensure", false, Process}, |  | ||||||
| 		{"ensure", false, EWayland}, |  | ||||||
| 
 |  | ||||||
| 		{"wayland", true, EWayland}, |  | ||||||
| 		{"x11", true, EX11}, |  | ||||||
| 		{"dbus", true, EDBus}, |  | ||||||
| 		{"pulseaudio", true, EPulse}, |  | ||||||
| 	} |  | ||||||
| 	for _, tc := range testCases { |  | ||||||
| 		t.Run(tc.want, func(t *testing.T) { |  | ||||||
| 			m := &mkdirOp{ |  | ||||||
| 				et:        tc.et, |  | ||||||
| 				path:      container.Nonexistent, |  | ||||||
| 				perm:      0701, |  | ||||||
| 				ephemeral: tc.ephemeral, |  | ||||||
| 			} |  | ||||||
| 			want := "mode: " + os.FileMode(0701).String() + " type: " + tc.want + ` path: "/proc/nonexistent"` |  | ||||||
| 			if got := m.String(); got != want { |  | ||||||
| 				t.Errorf("String() = %v, want %v", got, want) |  | ||||||
| 			} |  | ||||||
| 		}) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user