This is an automated email from the ASF dual-hosted git repository.
hsluoyz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/casbin-gateway.git
The following commit(s) were added to refs/heads/master by this push:
new 8ba981c fix(update): recognise the Gateway an update renamed when
claiming the port (#227)
8ba981c is described below
commit 8ba981c7a11488e839b173efb4997e17362334fe
Author: qioo777 <[email protected]>
AuthorDate: Tue Sep 15 21:20:27 2026 +0800
fix(update): recognise the Gateway an update renamed when claiming the port
(#227)
---
util/port.go | 21 +++++++++++++++++----
util/port_test.go | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 68 insertions(+), 4 deletions(-)
diff --git a/util/port.go b/util/port.go
index 8e4e824..e4e5d6a 100644
--- a/util/port.go
+++ b/util/port.go
@@ -49,6 +49,11 @@ const (
// waiting, which costs a netstat each time.
portStopInterval = 2 * time.Second
portClaimInterval = 250 * time.Millisecond
+ // updateBackupSuffix and updateFailedSuffix are what an update renames
the
+ // executable it replaces to. They mirror the version package's own
+ // constants, which cannot be imported here: that package imports this
one.
+ updateBackupSuffix = ".old"
+ updateFailedSuffix = ".failed"
)
// ListenTcp binds a TCP listener on all interfaces for the given port. Callers
@@ -217,16 +222,24 @@ func isSelfExecutable(name string) bool {
return mine == other
}
-// executableBaseName drops the directory and the ".exe" suffix and lowercases
-// the rest, so that "C:\Program Files\Casbin-Gateway.exe" and
-// "casbin-gateway" are recognised as the same program.
+// executableBaseName drops the directory, the suffix an update renamed the
file
+// to and the ".exe" suffix, and lowercases the rest, so that
+// "C:\Program Files\Casbin-Gateway.exe" and "casbin-gateway" are recognised as
+// the same program.
+//
+// The renamed suffix matters because a process is named after the file it runs
+// from as that file is now: an update renames the executable it is replacing
+// before the new Gateway starts, so the one still holding the port is reported
+// as "casbin-gateway.exe.old".
func executableBaseName(value string) string {
value = strings.TrimSpace(value)
if value == "" {
return ""
}
- return strings.TrimSuffix(strings.ToLower(filepath.Base(value)), ".exe")
+ name := strings.ToLower(filepath.Base(value))
+ name = strings.TrimSuffix(strings.TrimSuffix(name, updateFailedSuffix),
updateBackupSuffix)
+ return strings.TrimSuffix(name, ".exe")
}
// findListenerPid returns the pid of a process listening on the port, or 0
when
diff --git a/util/port_test.go b/util/port_test.go
index cae82cb..1b0feea 100644
--- a/util/port_test.go
+++ b/util/port_test.go
@@ -18,6 +18,7 @@ import (
"net"
"os"
"os/exec"
+ "path/filepath"
"strings"
"testing"
)
@@ -60,6 +61,56 @@ func TestParseNetstatPid(t *testing.T) {
}
}
+// TestExecutableBaseName covers the names the same program can be reported
+// under, including the ones an update leaves behind.
+func TestExecutableBaseName(t *testing.T) {
+ tests := []struct {
+ name string
+ value string
+ want string
+ }{
+ {"plain name", "casbin-gateway", "casbin-gateway"},
+ {"windows path", `C:\Program Files\Casbin-Gateway.exe`,
"casbin-gateway"},
+ {"replaced by an update", "casbin-gateway.exe.old",
"casbin-gateway"},
+ {"replaced by an update off windows", "casbin-gateway.old",
"casbin-gateway"},
+ {"set aside by a rollback", "casbin-gateway.exe.failed",
"casbin-gateway"},
+ {"another program", "nginx.exe", "nginx"},
+ {"nothing to name", " ", ""},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if got := executableBaseName(tt.value); got != tt.want {
+ t.Errorf("executableBaseName(%q) = %q, want
%q", tt.value, got, tt.want)
+ }
+ })
+ }
+}
+
+// TestIsSelfExecutableAcrossAnUpdate is the check a restart into an update
+// depends on. The update renames the executable it replaces before the new
+// Gateway starts, and a process is named after the file it runs from as that
+// file is now, so the Gateway still holding the port is reported under the
+// renamed name. Taking that for another program is what made the restarted
+// Gateway give up the port and exit instead of taking it over.
+func TestIsSelfExecutableAcrossAnUpdate(t *testing.T) {
+ self, err := os.Executable()
+ if err != nil {
+ t.Fatalf("os.Executable() error: %v", err)
+ }
+ name := filepath.Base(self)
+
+ for _, suffix := range []string{"", ".old", ".failed"} {
+ if !isSelfExecutable(name + suffix) {
+ t.Errorf("isSelfExecutable(%q) = false, want true",
name+suffix)
+ }
+ }
+
+ if isSelfExecutable("nginx.exe") {
+ t.Errorf(`isSelfExecutable("nginx.exe") = true, want false`)
+ }
+}
+
// TestDescribePortHolder checks the whole lookup against a port this test is
// holding itself. The platform commands it shells out to are not guaranteed to
// exist, so an empty answer is tolerated: the description is only ever a hint.
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]