system: partial I inherit dispatcher
	
		
			
	
		
	
	
		
	
		
			All checks were successful
		
		
	
	
		
			
				
	
				Test / Create distribution (push) Successful in 32s
				
			
		
			
				
	
				Test / Sandbox (push) Successful in 2m38s
				
			
		
			
				
	
				Test / Hakurei (push) Successful in 4m23s
				
			
		
			
				
	
				Test / Sandbox (race detector) (push) Successful in 5m34s
				
			
		
			
				
	
				Test / Hpkg (push) Successful in 6m42s
				
			
		
			
				
	
				Test / Hakurei (race detector) (push) Successful in 7m19s
				
			
		
			
				
	
				Test / Flake checks (push) Successful in 3m1s
				
			
		
		
	
	
				
					
				
			
		
			All checks were successful
		
		
	
	Test / Create distribution (push) Successful in 32s
				
			Test / Sandbox (push) Successful in 2m38s
				
			Test / Hakurei (push) Successful in 4m23s
				
			Test / Sandbox (race detector) (push) Successful in 5m34s
				
			Test / Hpkg (push) Successful in 6m42s
				
			Test / Hakurei (race detector) (push) Successful in 7m19s
				
			Test / Flake checks (push) Successful in 3m1s
				
			This enables I struct methods to be checked. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
		
							parent
							
								
									c8a0effe90
								
							
						
					
					
						commit
						6265aea73a
					
				| @ -4,7 +4,6 @@ package system | |||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"log" |  | ||||||
| 	"strings" | 	"strings" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| @ -116,14 +115,15 @@ func (sys *I) Commit() error { | |||||||
| 	sys.committed = true | 	sys.committed = true | ||||||
| 
 | 
 | ||||||
| 	sp := New(sys.ctx, sys.uid) | 	sp := New(sys.ctx, sys.uid) | ||||||
|  | 	sp.syscallDispatcher = sys.syscallDispatcher | ||||||
| 	sp.ops = make([]Op, 0, len(sys.ops)) // prevent copies during commits | 	sp.ops = make([]Op, 0, len(sys.ops)) // prevent copies during commits | ||||||
| 	defer func() { | 	defer func() { | ||||||
| 		// sp is set to nil when all ops are applied | 		// sp is set to nil when all ops are applied | ||||||
| 		if sp != nil { | 		if sp != nil { | ||||||
| 			// rollback partial commit | 			// rollback partial commit | ||||||
| 			msg.Verbosef("commit faulted after %d ops, rolling back partial commit", len(sp.ops)) | 			sys.verbosef("commit faulted after %d ops, rolling back partial commit", len(sp.ops)) | ||||||
| 			if err := sp.Revert(nil); err != nil { | 			if err := sp.Revert(nil); err != nil { | ||||||
| 				printJoinedError(log.Println, "cannot revert partial commit:", err) | 				printJoinedError(sys.println, "cannot revert partial commit:", err) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	}() | 	}() | ||||||
|  | |||||||
| @ -1,8 +1,15 @@ | |||||||
| package system | package system | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"errors" | ||||||
|  | 	"os" | ||||||
|  | 	"reflect" | ||||||
|  | 	"slices" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"testing" | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"hakurei.app/container/stub" | ||||||
|  | 	"hakurei.app/system/internal/xcb" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func TestCriteria(t *testing.T) { | func TestCriteria(t *testing.T) { | ||||||
| @ -153,3 +160,143 @@ func TestEqual(t *testing.T) { | |||||||
| 		}) | 		}) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestCommitRevert(t *testing.T) { | ||||||
|  | 	testCases := []struct { | ||||||
|  | 		name string | ||||||
|  | 		f    func(sys *I) | ||||||
|  | 		ec   Enablement | ||||||
|  | 
 | ||||||
|  | 		commit        []stub.Call | ||||||
|  | 		wantErrCommit error | ||||||
|  | 
 | ||||||
|  | 		revert        []stub.Call | ||||||
|  | 		wantErrRevert error | ||||||
|  | 	}{ | ||||||
|  | 		{"apply xhost partial mkdir", func(sys *I) { | ||||||
|  | 			sys. | ||||||
|  | 				Ephemeral(Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711). | ||||||
|  | 				ChangeHosts("chronos") | ||||||
|  | 		}, 0xff, []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), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"inserting entry %s to X11", []any{xhostOp("chronos")}}, nil, nil), | ||||||
|  | 			call("xcbChangeHosts", stub.ExpectArgs{xcb.HostMode(xcb.HostModeInsert), xcb.Family(xcb.FamilyServerInterpreted), "localuser\x00chronos"}, nil, stub.UniqueError(2)), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"commit faulted after %d ops, rolling back partial commit", []any{1}}, nil, nil), | ||||||
|  | 			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(3)), | ||||||
|  | 			call("println", stub.ExpectArgs{[]any{"cannot revert mkdir: unique error 3 injected by the test suite"}}, nil, nil), | ||||||
|  | 		}, &OpError{Op: "xhost", Err: stub.UniqueError(2)}, nil, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"apply xhost", func(sys *I) { | ||||||
|  | 			sys. | ||||||
|  | 				Ephemeral(Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711). | ||||||
|  | 				ChangeHosts("chronos") | ||||||
|  | 		}, 0xff, []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), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"inserting entry %s to X11", []any{xhostOp("chronos")}}, nil, nil), | ||||||
|  | 			call("xcbChangeHosts", stub.ExpectArgs{xcb.HostMode(xcb.HostModeInsert), xcb.Family(xcb.FamilyServerInterpreted), "localuser\x00chronos"}, nil, stub.UniqueError(2)), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"commit faulted after %d ops, rolling back partial commit", []any{1}}, nil, nil), | ||||||
|  | 			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), | ||||||
|  | 		}, &OpError{Op: "xhost", Err: stub.UniqueError(2)}, nil, nil}, | ||||||
|  | 
 | ||||||
|  | 		{"revert multi", func(sys *I) { | ||||||
|  | 			sys. | ||||||
|  | 				Ephemeral(Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711). | ||||||
|  | 				ChangeHosts("chronos") | ||||||
|  | 		}, 0xff, []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), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"inserting entry %s to X11", []any{xhostOp("chronos")}}, nil, nil), | ||||||
|  | 			call("xcbChangeHosts", stub.ExpectArgs{xcb.HostMode(xcb.HostModeInsert), xcb.Family(xcb.FamilyServerInterpreted), "localuser\x00chronos"}, nil, nil), | ||||||
|  | 		}, nil, []stub.Call{ | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"deleting entry %s from X11", []any{xhostOp("chronos")}}, nil, nil), | ||||||
|  | 			call("xcbChangeHosts", stub.ExpectArgs{xcb.HostMode(xcb.HostModeDelete), xcb.Family(xcb.FamilyServerInterpreted), "localuser\x00chronos"}, nil, stub.UniqueError(1)), | ||||||
|  | 			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)), | ||||||
|  | 		}, errors.Join( | ||||||
|  | 			&OpError{Op: "xhost", Err: stub.UniqueError(1), Revert: true}, | ||||||
|  | 			&OpError{Op: "mkdir", Err: stub.UniqueError(0), Revert: true})}, | ||||||
|  | 
 | ||||||
|  | 		{"success", func(sys *I) { | ||||||
|  | 			sys. | ||||||
|  | 				Ephemeral(Process, "/tmp/hakurei.0/f2f3bcd492d0266438fa9bf164fe90d9", 0711). | ||||||
|  | 				ChangeHosts("chronos") | ||||||
|  | 		}, 0xff, []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), | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"inserting entry %s to X11", []any{xhostOp("chronos")}}, nil, nil), | ||||||
|  | 			call("xcbChangeHosts", stub.ExpectArgs{xcb.HostMode(xcb.HostModeInsert), xcb.Family(xcb.FamilyServerInterpreted), "localuser\x00chronos"}, nil, nil), | ||||||
|  | 		}, nil, []stub.Call{ | ||||||
|  | 			call("verbosef", stub.ExpectArgs{"deleting entry %s from X11", []any{xhostOp("chronos")}}, nil, nil), | ||||||
|  | 			call("xcbChangeHosts", stub.ExpectArgs{xcb.HostMode(xcb.HostModeDelete), xcb.Family(xcb.FamilyServerInterpreted), "localuser\x00chronos"}, nil, nil), | ||||||
|  | 			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}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	for _, tc := range testCases { | ||||||
|  | 		t.Run(tc.name, func(t *testing.T) { | ||||||
|  | 			var ec *Criteria | ||||||
|  | 			if tc.ec != 0xff { | ||||||
|  | 				ec = (*Criteria)(&tc.ec) | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			sys, s := InternalNew(t, stub.Expect{Calls: slices.Concat(tc.commit, []stub.Call{{Name: stub.CallSeparator}}, tc.revert)}, 0xbad) | ||||||
|  | 			defer stub.HandleExit(t) | ||||||
|  | 			tc.f(sys) | ||||||
|  | 			errCommit := sys.Commit() | ||||||
|  | 			s.Expects(stub.CallSeparator) | ||||||
|  | 			if !reflect.DeepEqual(errCommit, tc.wantErrCommit) { | ||||||
|  | 				t.Errorf("Commit: error = %v, want %v", errCommit, tc.wantErrCommit) | ||||||
|  | 			} | ||||||
|  | 			if errCommit != nil { | ||||||
|  | 				goto out | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			if err := sys.Revert(ec); !reflect.DeepEqual(err, tc.wantErrRevert) { | ||||||
|  | 				t.Errorf("Revert: error = %v, want %v", err, tc.wantErrRevert) | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 		out: | ||||||
|  | 			s.VisitIncomplete(func(s *stub.Stub[syscallDispatcher]) { | ||||||
|  | 				count := s.Pos() - 1 // separator | ||||||
|  | 				if count < len(tc.commit) { | ||||||
|  | 					t.Errorf("Commit: %d calls, want %d", count, len(tc.commit)) | ||||||
|  | 				} else { | ||||||
|  | 					t.Errorf("Revert: %d calls, want %d", count-len(tc.commit), len(tc.revert)) | ||||||
|  | 				} | ||||||
|  | 			}) | ||||||
|  | 		}) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	t.Run("panic", func(t *testing.T) { | ||||||
|  | 		t.Run("committed", func(t *testing.T) { | ||||||
|  | 			defer func() { | ||||||
|  | 				want := "attempting to commit twice" | ||||||
|  | 				if r := recover(); r != want { | ||||||
|  | 					t.Errorf("Commit: panic = %v, want %v", r, want) | ||||||
|  | 				} | ||||||
|  | 			}() | ||||||
|  | 			_ = (&I{committed: true}).Commit() | ||||||
|  | 		}) | ||||||
|  | 
 | ||||||
|  | 		t.Run("reverted", func(t *testing.T) { | ||||||
|  | 			defer func() { | ||||||
|  | 				want := "attempting to revert twice" | ||||||
|  | 				if r := recover(); r != want { | ||||||
|  | 					t.Errorf("Revert: panic = %v, want %v", r, want) | ||||||
|  | 				} | ||||||
|  | 			}() | ||||||
|  | 			_ = (&I{reverted: true}).Revert(nil) | ||||||
|  | 		}) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestNop(t *testing.T) { | ||||||
|  | 	// these do nothing | ||||||
|  | 	new(noCopy).Unlock() | ||||||
|  | 	new(noCopy).Lock() | ||||||
|  | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user