summaryrefslogtreecommitdiffstats
path: root/dependencies/pkg/mod/golang.org/x/sys@v0.1.0/unix/syscall_internal_solaris_test.go
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 12:36:04 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 12:36:04 +0000
commitb09c6d56832eb1718c07d74abf3bc6ae3fe4e030 (patch)
treed2caec2610d4ea887803ec9e9c3cd77136c448ba /dependencies/pkg/mod/golang.org/x/sys@v0.1.0/unix/syscall_internal_solaris_test.go
parentInitial commit. (diff)
downloadicingadb-b09c6d56832eb1718c07d74abf3bc6ae3fe4e030.tar.xz
icingadb-b09c6d56832eb1718c07d74abf3bc6ae3fe4e030.zip
Adding upstream version 1.1.0.upstream/1.1.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dependencies/pkg/mod/golang.org/x/sys@v0.1.0/unix/syscall_internal_solaris_test.go')
-rw-r--r--dependencies/pkg/mod/golang.org/x/sys@v0.1.0/unix/syscall_internal_solaris_test.go236
1 files changed, 236 insertions, 0 deletions
diff --git a/dependencies/pkg/mod/golang.org/x/sys@v0.1.0/unix/syscall_internal_solaris_test.go b/dependencies/pkg/mod/golang.org/x/sys@v0.1.0/unix/syscall_internal_solaris_test.go
new file mode 100644
index 0000000..a92753a
--- /dev/null
+++ b/dependencies/pkg/mod/golang.org/x/sys@v0.1.0/unix/syscall_internal_solaris_test.go
@@ -0,0 +1,236 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build solaris
+// +build solaris
+
+package unix
+
+import (
+ "fmt"
+ "os"
+ "runtime"
+ "testing"
+)
+
+func (e *EventPort) checkInternals(t *testing.T, fds, paths, cookies, pending int) {
+ t.Helper()
+ p, err := e.Pending()
+ if err != nil {
+ t.Fatalf("failed to query how many events are pending")
+ }
+ if len(e.fds) != fds || len(e.paths) != paths || len(e.cookies) != cookies || p != pending {
+ format := "| fds: %d | paths: %d | cookies: %d | pending: %d |"
+ expected := fmt.Sprintf(format, fds, paths, cookies, pending)
+ got := fmt.Sprintf(format, len(e.fds), len(e.paths), len(e.cookies), p)
+ t.Errorf("Internal state mismatch\nfound: %s\nexpected: %s", got, expected)
+ }
+}
+
+// Regression test for DissociatePath returning ENOENT
+// This test is intended to create a linear worst
+// case scenario of events being associated and
+// fired but not consumed before additional
+// calls to dissociate and associate happen
+// This needs to be an internal test so that
+// we can validate the state of the private maps
+func TestEventPortDissociateAlreadyGone(t *testing.T) {
+ port, err := NewEventPort()
+ if err != nil {
+ t.Fatalf("failed to create an EventPort")
+ }
+ defer port.Close()
+ dir := t.TempDir()
+ tmpfile, err := os.CreateTemp(dir, "eventport")
+ if err != nil {
+ t.Fatalf("unable to create a tempfile: %v", err)
+ }
+ path := tmpfile.Name()
+ stat, err := os.Stat(path)
+ if err != nil {
+ t.Fatalf("unexpected failure to Stat file: %v", err)
+ }
+ err = port.AssociatePath(path, stat, FILE_MODIFIED, "cookie1")
+ if err != nil {
+ t.Fatalf("unexpected failure associating file: %v", err)
+ }
+ // We should have 1 path registered and 1 cookie in the jar
+ port.checkInternals(t, 0, 1, 1, 0)
+ // The path is associated, let's delete it.
+ err = os.Remove(path)
+ if err != nil {
+ t.Fatalf("unexpected failure deleting file: %v", err)
+ }
+ // The file has been deleted, some sort of pending event is probably
+ // queued in the kernel waiting for us to get it AND the kernel is
+ // no longer watching for events on it. BUT... Because we haven't
+ // consumed the event, this API thinks it's still watched:
+ watched := port.PathIsWatched(path)
+ if !watched {
+ t.Errorf("unexpected result from PathIsWatched")
+ }
+ // Ok, let's dissociate the file even before reading the event.
+ // Oh, ENOENT. I guess it's not associated any more
+ err = port.DissociatePath(path)
+ if err != ENOENT {
+ t.Errorf("unexpected result dissociating a seemingly associated path we know isn't: %v", err)
+ }
+ // As established by the return value above, this should clearly be false now:
+ // Narrator voice: in the first version of this API, it wasn't.
+ watched = port.PathIsWatched(path)
+ if watched {
+ t.Errorf("definitively unwatched file still in the map")
+ }
+ // We should have nothing registered, but 1 pending event corresponding
+ // to the cookie in the jar
+ port.checkInternals(t, 0, 0, 1, 1)
+ f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ err = f.Close()
+ if err != nil {
+ t.Fatalf("unexpected failure closing file: %v", err)
+ }
+ stat, err = os.Stat(path)
+ if err != nil {
+ t.Fatalf("unexpected failure to Stat file: %v", err)
+ }
+ c := "cookie2" // c is for cookie, that's good enough for me
+ err = port.AssociatePath(path, stat, FILE_MODIFIED, c)
+ if err != nil {
+ t.Errorf("unexpected failure associating file: %v", err)
+ }
+ // We should have 1 registered path and its cookie
+ // as well as a second cookie corresponding to the pending event
+ port.checkInternals(t, 0, 1, 2, 1)
+
+ // Fire another event
+ err = os.Remove(path)
+ if err != nil {
+ t.Fatalf("unexpected failure deleting file: %v", err)
+ }
+ port.checkInternals(t, 0, 1, 2, 2)
+ err = port.DissociatePath(path)
+ if err != ENOENT {
+ t.Errorf("unexpected result dissociating a seemingly associated path we know isn't: %v", err)
+ }
+ // By dissociating this path after deletion we ensure that the paths map is now empty
+ // If we're not careful we could trigger a nil pointer exception
+ port.checkInternals(t, 0, 0, 2, 2)
+
+ f, err = os.OpenFile(path, os.O_WRONLY|os.O_CREATE, 0666)
+ if err != nil {
+ t.Fatalf("creating test file failed: %s", err)
+ }
+ err = f.Close()
+ if err != nil {
+ t.Fatalf("unexpected failure closing file: %v", err)
+ }
+ stat, err = os.Stat(path)
+ if err != nil {
+ t.Fatalf("unexpected failure to Stat file: %v", err)
+ }
+ // Put a seemingly duplicate cookie in the jar to see if we can trigger an incorrect removal from the paths map
+ err = port.AssociatePath(path, stat, FILE_MODIFIED, c)
+ if err != nil {
+ t.Errorf("unexpected failure associating file: %v", err)
+ }
+ port.checkInternals(t, 0, 1, 3, 2)
+
+ // run the garbage collector so that if we messed up it should be painfully clear
+ runtime.GC()
+
+ // Before the fix, this would cause a nil pointer exception
+ e, err := port.GetOne(nil)
+ if err != nil {
+ t.Errorf("failed to get an event: %v", err)
+ }
+ port.checkInternals(t, 0, 1, 2, 1)
+ if e.Cookie != "cookie1" {
+ t.Errorf(`expected "cookie1", got "%v"`, e.Cookie)
+ }
+ // Make sure that a cookie of the same value doesn't cause removal from the paths map incorrectly
+ e, err = port.GetOne(nil)
+ if err != nil {
+ t.Errorf("failed to get an event: %v", err)
+ }
+ port.checkInternals(t, 0, 1, 1, 0)
+ if e.Cookie != "cookie2" {
+ t.Errorf(`expected "cookie2", got "%v"`, e.Cookie)
+ }
+
+ err = os.Remove(path)
+ if err != nil {
+ t.Fatalf("unexpected failure deleting file: %v", err)
+ }
+ // Event has fired, but until processed it should still be in the map
+ port.checkInternals(t, 0, 1, 1, 1)
+ e, err = port.GetOne(nil)
+ if err != nil {
+ t.Errorf("failed to get an event: %v", err)
+ }
+ if e.Cookie != "cookie2" {
+ t.Errorf(`expected "cookie2", got "%v"`, e.Cookie)
+ }
+ // The maps should be empty and there should be no pending events
+ port.checkInternals(t, 0, 0, 0, 0)
+}
+
+// Regression test for spuriously triggering a panic about memory mismanagement
+// that can be triggered by an event processing thread trying to process an event
+// after a different thread has already called port.Close().
+// Implemented as an internal test so that we can just simulate the Close()
+// because if you call close first in the same thread, things work properly
+// anyway.
+func TestEventPortGetAfterClose(t *testing.T) {
+ port, err := NewEventPort()
+ if err != nil {
+ t.Fatalf("NewEventPort failed: %v", err)
+ }
+ // Create, associate, and delete 2 files
+ for i := 0; i < 2; i++ {
+ tmpfile, err := os.CreateTemp("", "eventport")
+ if err != nil {
+ t.Fatalf("unable to create tempfile: %v", err)
+ }
+ path := tmpfile.Name()
+ stat, err := os.Stat(path)
+ if err != nil {
+ t.Fatalf("unable to stat tempfile: %v", err)
+ }
+ err = port.AssociatePath(path, stat, FILE_MODIFIED, nil)
+ if err != nil {
+ t.Fatalf("unable to AssociatePath tempfile: %v", err)
+ }
+ err = os.Remove(path)
+ if err != nil {
+ t.Fatalf("unable to Remove tempfile: %v", err)
+ }
+ }
+ n, err := port.Pending()
+ if err != nil {
+ t.Errorf("Pending failed: %v", err)
+ }
+ if n != 2 {
+ t.Errorf("expected 2 pending events, got %d", n)
+ }
+ // Simulate a close from a different thread
+ port.fds = nil
+ port.paths = nil
+ port.cookies = nil
+ // Ensure that we get back reasonable errors rather than panic
+ _, err = port.GetOne(nil)
+ if err == nil || err.Error() != "this EventPort is already closed" {
+ t.Errorf("didn't receive expected error of 'this EventPort is already closed'; got: %v", err)
+ }
+ events := make([]PortEvent, 2)
+ n, err = port.Get(events, 1, nil)
+ if n != 0 {
+ t.Errorf("expected to get back 0 events, got %d", n)
+ }
+ if err == nil || err.Error() != "this EventPort is already closed" {
+ t.Errorf("didn't receive expected error of 'this EventPort is already closed'; got: %v", err)
+ }
+}