mirror of
https://github.com/kerberos-io/onvif.git
synced 2026-08-23 15:08:33 +00:00
Previously stream.go was a 621-line monolith holding the Stream type,
SOAP plumbing, pull loop, renew loop, recreate logic and jitter. The
test side had grown five orphan files (renew_test.go, reconnect_test.go,
soap_test.go, jitter_test.go, coverage_test.go) with no matching source
files. The mismatch made it harder than necessary to find the code
that backed a given test.
This commit splits stream.go by concern so each source file has its
own test file alongside it. Files <100 LOC (errors, jitter) were folded
into their conceptual parents rather than left as fragments.
New layout — 8 source + 8 test + helpers (test utility) + doc:
stream.go <-> stream_test.go Stream type, Options, lifecycle
soap.go <-> soap_test.go SOAP plumbing + fault detection
renew.go <-> renew_test.go Renew loop and absolute time
reconnect.go <-> reconnect_test.go Pull loop, recreate, jitter
decode.go <-> decode_test.go NotificationMessage -> Event
types.go <-> types_test.go Event types + typed errors
topics.go <-> topics_test.go Classifier table
doc.go Package godoc landing page
helpers_test.go waitFor (test-only utility)
Mergers
-------
* errors.go (typed error wrappers, 42 LOC) -> types.go. ErrPullFailed /
ErrRenewFailed / ErrRecreateFailed are part of the type system, not a
separate concern.
* jitter.go (40 LOC) -> reconnect.go. jitter is an implementation detail
of attemptRecreate, used nowhere else.
Test distribution
-----------------
* coverage_test.go was a catch-all; tests moved to the file matching
the function under test:
- Close*, NewStream_*, FakeCaller_* -> stream_test.go
- DisableReconnect_*, RecreateResets_*, PullPointMutation_* ->
reconnect_test.go
- Decode_*, ExtractState_* -> decode_test.go
* soap_test.go shed the two orphans that did not belong there:
- TestRenew_SendsAbsoluteDateTimeNotDuration -> renew_test.go
- TestClose_BoundedByTimeoutOnHungUnsubscribe -> stream_test.go
* errors_test.go's pure type tests -> types_test.go
* errors_test.go's Stream-integration tests -> reconnect_test.go
* jitter_test.go -> reconnect_test.go
No behaviour change. Test suite passes -race clean.
87 lines
2.7 KiB
Go
87 lines
2.7 KiB
Go
package stream
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
// --- SOAP fault detection ---------------------------------------------
|
|
|
|
func TestExtractSOAPFault_SOAP11(t *testing.T) {
|
|
body := `<?xml version="1.0"?>
|
|
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
|
|
<env:Body>
|
|
<env:Fault>
|
|
<faultcode>env:Client</faultcode>
|
|
<faultstring>The action requested requires authorization and the sender is not authorized</faultstring>
|
|
</env:Fault>
|
|
</env:Body>
|
|
</env:Envelope>`
|
|
got := extractSOAPFault(body)
|
|
assert.Contains(t, got, "not authorized")
|
|
}
|
|
|
|
func TestExtractSOAPFault_SOAP12(t *testing.T) {
|
|
body := `<?xml version="1.0"?>
|
|
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
|
|
<env:Body>
|
|
<env:Fault>
|
|
<env:Code><env:Value>env:Sender</env:Value></env:Code>
|
|
<env:Reason><env:Text xml:lang="en">Subscription has expired</env:Text></env:Reason>
|
|
</env:Fault>
|
|
</env:Body>
|
|
</env:Envelope>`
|
|
got := extractSOAPFault(body)
|
|
assert.Contains(t, got, "Subscription has expired")
|
|
}
|
|
|
|
func TestExtractSOAPFault_NotAFault(t *testing.T) {
|
|
assert.Empty(t, extractSOAPFault(createPullPointResp))
|
|
}
|
|
|
|
func TestExtractSOAPFault_EmptyBody(t *testing.T) {
|
|
assert.Empty(t, extractSOAPFault(""))
|
|
}
|
|
|
|
func TestUnmarshalNode_ReturnsFaultReasonInsteadOfMissingElement(t *testing.T) {
|
|
body := `<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
|
|
<env:Body><env:Fault><faultstring>not authorized</faultstring></env:Fault></env:Body>
|
|
</env:Envelope>`
|
|
var out struct{}
|
|
err := unmarshalNode(body, "PullMessagesResponse", &out)
|
|
require.Error(t, err)
|
|
assert.Contains(t, err.Error(), "not authorized")
|
|
assert.NotContains(t, err.Error(), "missing PullMessagesResponse")
|
|
}
|
|
|
|
// --- Bounded body read -----------------------------------------------
|
|
|
|
func TestReadClose_LimitsBodySize(t *testing.T) {
|
|
if maxResponseBytes < 1024 {
|
|
t.Skip("limit too small for this test")
|
|
}
|
|
big := strings.Repeat("A", maxResponseBytes+1024)
|
|
body := "<env:Envelope><env:Body>" + big + "</env:Body></env:Envelope>"
|
|
fc := newFakeCaller()
|
|
fc.queueCallMethod(body, nil)
|
|
// Construction will fail because the truncated body has no
|
|
// CreatePullPointSubscriptionResponse — that's fine; what matters is
|
|
// the read completes without OOM.
|
|
_, err := newStream(testContext(t), fc, Options{})
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
// testContext returns a Background context already wired to cancel via
|
|
// t.Cleanup so the test does not need to manage the cancellation
|
|
// goroutine inline.
|
|
func testContext(t *testing.T) context.Context {
|
|
t.Helper()
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
t.Cleanup(cancel)
|
|
return ctx
|
|
}
|