package syncapi_test import ( "testing" "github.com/dariuszjaniak/warp/server/internal/syncapi" ) func TestTokenRoundTrips(t *testing.T) { for _, tc := range []struct { name string token syncapi.Token want string }{ {"the initial token", syncapi.Token{}, "s0"}, {"events only", syncapi.Token{PDU: 12}, "s12"}, {"events and receipts", syncapi.Token{PDU: 12, Receipt: 3}, "s12_3"}, { "every stream", syncapi.Token{PDU: 1, Receipt: 2, ToDevice: 3, AccountData: 4, Presence: 5, DeviceList: 6}, "s1_2_3_4_5_6", }, { // /messages pages back into history backfilled from other // servers, which is numbered downwards from -1. "a position inside backfilled history", syncapi.Token{PDU: -7}, "s-7", }, { // A zero in the middle has to be written, because the // positions are read by place. "a gap in the middle", syncapi.Token{PDU: 1, Presence: 5}, "s1_0_0_0_5", }, } { t.Run(tc.name, func(t *testing.T) { if got := tc.token.String(); got != tc.want { t.Fatalf("String() = %q, want %q", got, tc.want) } parsed, err := syncapi.ParseToken(tc.want) if err != nil { t.Fatalf("ParseToken(%q): %v", tc.want, err) } if parsed != tc.token { t.Errorf("ParseToken(%q) = %+v, want %+v", tc.want, parsed, tc.token) } }) } } func TestParseTokenAcceptsAnEmptyString(t *testing.T) { // /sync without ?since= and /messages without ?from= both mean "from // the beginning"; refusing the empty string would make every caller // special-case it. parsed, err := syncapi.ParseToken("") if err != nil { t.Fatalf("ParseToken(\"\"): %v", err) } if !parsed.IsInitial() { t.Errorf("ParseToken(\"\") = %+v, want the initial token", parsed) } } func TestParseTokenAcceptsAShortToken(t *testing.T) { // A token a client stored before a stream existed must go on working: // the stream it does not mention reads as "seen nothing", so the // client is sent that stream in full once and is in step afterwards. parsed, err := syncapi.ParseToken("s7") if err != nil { t.Fatalf("ParseToken(\"s7\"): %v", err) } if parsed.PDU != 7 { t.Errorf("PDU = %d, want 7", parsed.PDU) } if parsed.Receipt != 0 || parsed.ToDevice != 0 || parsed.AccountData != 0 || parsed.Presence != 0 { t.Errorf("the streams a short token omits must read as zero: %+v", parsed) } } func TestParseTokenRejectsNonsense(t *testing.T) { for _, raw := range []string{ "nonsense", // no prefix "t1_2", // a prefix this build does not write "s", // a prefix and nothing else "s1_-1", // a negative position outside the event stream "sx", // not a number "s1_", // a trailing separator "s1_2_3_4_5_6_7", // more positions than there are streams "s1.5", } { if _, err := syncapi.ParseToken(raw); err == nil { t.Errorf("ParseToken(%q) was accepted", raw) } } } func TestParseTokenIsNotFooledByOverflow(t *testing.T) { // A position larger than an int64 is not a position this server ever // handed out, and silently wrapping it would mean a client being sent // the whole of every room again. if _, err := syncapi.ParseToken("s99999999999999999999"); err == nil { t.Error("a position that does not fit in an int64 was accepted") } }