Repository navigation
Real World Server Behaviours
Real news servers don't all follow RFC 3977 to the letter. A client or cache that works against the plain Store server can still fail against them. The options below make the fake server behave like such servers. Each one has a test in realworld_test.go, and NewsCache runs its server against them in tests/e2e/upstream_test.go.
| Real-world behaviour | How to get it |
|---|---|
| Expired and cancelled articles leave gaps; numbers are never reused |
RemoveArticle, Expire, Cancel (the high-water mark stays) |
| A group whose articles all expired | remove them all: Low = High+1, or report 211 0 0 0 with GroupNumbers
|
| The last number goes down (newest articles cancelled) | GroupNumbers: st.HighestExisting |
| Frontends of a server farm that lag behind each other |
GroupNumbers with a lower High on some connections |
| Big article numbers (binary groups above 2^31, above 6×10^10) |
Article.Number, or a generated group with a high Low
|
| Very large groups (10^7 articles and more) |
Store.AddGenerated (see Store and Groups) |
| An overview database out of step with the spool (a record's Message-ID isn't the article's) | StoreOptions.OverviewFields |
| Several upstream servers with their own numbers for the same group | two servers, each with its own Store (example below) |
| Old LISTGROUP without ranges (RFC 977/2980) |
ListgroupRange: "reject" (501) or "ignore" (whole group) |
| Only OVER, or only XOVER |
NoXover, NoOver
|
| No NEWNEWS |
NoNewnews (500), or INN's 502 with Faults.Override "NEWNEWS"
|
| A transit peer without streaming (innfeed and innxmit fall back to IHAVE) |
PeerOptions.NoStream (see Fake Server) |
| A peer that refuses articles after reading them (a content filter) |
PeerOptions.Reject (TAKETHIS 439, IHAVE 437) |
| A peer that is busy for a moment |
PeerOptions.Defer431Once (CHECK 431), Defer436Once (IHAVE 436) |
| 420, or an empty 224, for a range without articles | EmptyOverReply |
| OVER replies capped at N records, whatever the range | MaxOverRange |
| An error for too large a range |
MaxOverRange with OverRangeTooLarge
|
| A connection limit |
Options.MaxConns (502 Too many connections, or MaxConnsGreeting such as 400 Too many users) |
| A login that times out mid-session |
StoreOpts.User/Pass with an Override 480 and OverrideFrom/OverrideTimes
|
| A slow server |
Delay, LineDelay, Drip
|
| Connections cut in the middle of a reply |
DropInMultiline, CloseAfter
|
| One failing article in a pipeline |
OverrideLine ("ARTICLE 2") |
| Overlong lines, replies that never end |
LongLine, Endless
|
| Another LIST OVERVIEW.FMT |
OverviewFmt (the OVER lines keep the default order; OverviewFields changes them) |
A server farm whose even-numbered connections lag five articles behind, with old LISTGROUP, no OVER, 420 for empty ranges, at most 10 records per XOVER and two connections:
st := fakeserver.NewStore()
for i := 0; i < 20; i++ {
st.AddArticle("alt.test", fakeserver.Article{})
}
lag := func(conn int, g fakeserver.Group) fakeserver.Group {
if conn%2 == 0 { // every second connection lags 5 articles behind
g.High -= 5
g.Count -= 5
}
return g
}
s := fakeserver.New(t, fakeserver.Options{
Store: st,
StoreOpts: fakeserver.StoreOptions{
GroupNumbers: lag,
ListgroupRange: "reject",
NoOver: true,
EmptyOverReply: []string{"420 No article(s) selected"},
MaxOverRange: 10,
},
MaxConns: 2,
})
// connection 1: "211 20 1 20 alt.test", connection 2: "211 15 1 15 alt.test",
// "LISTGROUP alt.test 1-5": 501, "XOVER 1-20": 10 records, "XOVER 30-40": 420,
// a third connection: "502 Too many connections"The last number going down:
s := fakeserver.New(t, fakeserver.Options{
Store: st,
StoreOpts: fakeserver.StoreOptions{GroupNumbers: st.HighestExisting},
})
st.Cancel("<5.alt.test@fakeserver.invalid>") // GROUP now says "211 4 1 4 alt.test"Several upstream servers that carry the same group with their own numbers:
a := fakeserver.NewStore()
b := fakeserver.NewStore()
for i := int64(1); i <= 4; i++ {
id := fmt.Sprintf("<%d@example.invalid>", i)
a.AddArticle("test.beta", fakeserver.Article{Number: i, MessageID: id})
b.AddArticle("test.beta", fakeserver.Article{Number: 100 + i, MessageID: id})
}
srvA := fakeserver.New(t, fakeserver.Options{Store: a}) // "211 4 1 4 test.beta"
srvB := fakeserver.New(t, fakeserver.Options{Store: b}) // "211 4 101 104 test.beta"NewsCache's upstreams_test.go
uses generated groups, OverviewFields and two servers like this.
A full disk, or a process without file descriptors left, happens on the
side of the server under test, not in the fake server.
proc.Options.Ulimit sets such limits for a server binary (see
Running Server Binaries).
-
OVER lines in another field order without an
OverviewFieldsfunction:OverviewFmtonly changes the LIST OVERVIEW.FMT answer. -
STARTTLS, COMPRESS, XHDR, HDR, IHAVE in the Store server (IHAVE is
answered by
PeerHandler).
When a test needs a behaviour that isn't here, add it to the kit (see Development).
nntp-testkit is free software under the GNU General Public License, version 2 — see LICENSE.