79 lines
2.9 KiB
Go
79 lines
2.9 KiB
Go
package stacks
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"log"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// R-1323: the checked FileBrowser container can be replaced between the check and the leave (the image moved at start).
|
|
// „No such container" then means the OLD one is gone, not that every app still reaches FileBrowser. The line reads the
|
|
// CURRENT container's networks and says what is true; a current container that IS on the app network keeps the alarm.
|
|
//
|
|
// RED-PROOF (2026-11-02): before the fix the first case logged „could not leave traefik-public — every app can still reach
|
|
// it … No such container" (seen on 9202, 0.346.1-rc.1, 2026-10-27), and this fails on that line.
|
|
func r1323Rig(t *testing.T, currentOnApps bool) (*Manager, *bytes.Buffer) {
|
|
t.Helper()
|
|
fb := &fakeFB{password: "admin"}
|
|
srv := httptest.NewServer(fb.handler())
|
|
t.Cleanup(srv.Close)
|
|
m, _, _ := fbManager(t, srv.URL)
|
|
var buf bytes.Buffer
|
|
m.logger = log.New(&buf, "", 0)
|
|
runs := []string{"old111 2026-10-27T14:58:15Z"}
|
|
m.fbStarted = func() string {
|
|
r := runs[0]
|
|
if len(runs) > 1 {
|
|
runs = runs[1:]
|
|
}
|
|
return r
|
|
}
|
|
nets := map[string]bool{"old111@traefik-public": true, "new222@traefik-public": currentOnApps}
|
|
m.fbNetOnFn = func(c, n string) bool { return nets[c+"@"+n] }
|
|
m.fbNetConnectFn = func(c, n string) error { nets[c+"@"+n] = true; return nil }
|
|
m.fbNetDisconnectFn = func(c, n string) error {
|
|
if c == "old111" {
|
|
runs = []string{"new222 2026-10-27T14:58:17Z"} // the recreate won the race
|
|
return errors.New("Error response from daemon: No such container: old111")
|
|
}
|
|
return nil
|
|
}
|
|
m.fbNetEnsureFn = func(string) error { return nil }
|
|
m.fbOfficeLinkedFn = func() (bool, bool) { return false, false }
|
|
return m, &buf
|
|
}
|
|
|
|
func TestR1323_AReplacedContainerIsNotReportedAsExposed(t *testing.T) {
|
|
m, buf := r1323Rig(t, false)
|
|
m.fileBrowserGateLocked()
|
|
got := buf.String()
|
|
if strings.Contains(got, "every app can still reach it") {
|
|
t.Fatalf("a false alarm for a container that is gone: %q", got)
|
|
}
|
|
if !strings.Contains(got, "new222") || !strings.Contains(got, "not on traefik-public") {
|
|
t.Fatalf("the line must name the current container and the truth: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestR1323_ACurrentContainerOnTheAppNetworkKeepsTheAlarm(t *testing.T) {
|
|
m, buf := r1323Rig(t, true)
|
|
m.fileBrowserGateLocked()
|
|
got := buf.String()
|
|
if !strings.Contains(got, "every app can still reach it") || !strings.Contains(got, "new222") {
|
|
t.Fatalf("the replacement IS on the app network: the alarm stays, naming it: %q", got)
|
|
}
|
|
}
|
|
|
|
// Any other failure to leave keeps the alarm as before (control).
|
|
func TestR1323_AnotherDisconnectFailureKeepsTheAlarm(t *testing.T) {
|
|
m, buf := r1323Rig(t, false)
|
|
m.fbNetDisconnectFn = func(c, n string) error { return errors.New("daemon busy") }
|
|
m.fileBrowserGateLocked()
|
|
if got := buf.String(); !strings.Contains(got, "every app can still reach it") || !strings.Contains(got, "daemon busy") {
|
|
t.Fatalf("a real failure to leave must keep its alarm: %q", got)
|
|
}
|
|
}
|