Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F7892497
paginate-test.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
7 KB
Referenced Files
None
Subscribers
None
paginate-test.cpp
View Options
/*
* This file is part of libkazv.
* SPDX-FileCopyrightText: 2021-2023 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
#include
<libkazv-config.hpp>
#include
<catch2/catch_all.hpp>
#include
<boost/asio.hpp>
#include
<asio-promise-handler.hpp>
#include
<cursorutil.hpp>
#include
<sdk-model.hpp>
#include
<client/client.hpp>
#include
"client-test-util.hpp"
#include
"factory.hpp"
#include
<iostream>
using
namespace
Kazv
;
using
namespace
Kazv
::
Factory
;
using
Catch
::
Matchers
::
ContainsSubstring
;
using
Catch
::
Matchers
::
Contains
;
// adapted from https://matrix.org/docs/spec/client_server/latest#get-matrix-client-r0-rooms-roomid-messages
static
json
paginateResponseJson
=
R
"
(
{
"start": "prevBatchForEvent1",
"end": "anotherPrevBatch",
"chunk": [
{
"content": {
"body": "This is an example text message",
"msgtype": "m.text",
"format": "org.matrix.custom.html",
"formatted_body": "<b>This is an example text message</b>"
},
"type": "m.room.message",
"event_id": "$third:example.org",
"room_id": "!foo:example.org",
"sender": "@example:example.org",
"origin_server_ts": 1432735824653,
"unsigned": {
"age": 1234
}
},
{
"content": {
"name": "The room name"
},
"type": "m.room.name",
"event_id": "$second:example.org",
"room_id": "!foo:example.org",
"sender": "@example:example.org",
"origin_server_ts": 1432735824653,
"unsigned": {
"age": 1234
},
"state_key": ""
},
{
"content": {
"body": "Gangnam Style",
"url": "mxc://example.org/a526eYUSFFxlgbQYZmo442",
"info": {
"thumbnail_url": "mxc://example.org/FHyPlCeYUSFFxlgbQYZmoEoe",
"thumbnail_info": {
"mimetype": "image/jpeg",
"size": 46144,
"w": 300,
"h": 300
},
"w": 480,
"h": 320,
"duration": 2140786,
"size": 1563685,
"mimetype": "video/mp4"
},
"msgtype": "m.video"
},
"type": "m.room.message",
"event_id": "$first:example.org",
"room_id": "!foo:example.org",
"sender": "@example:example.org",
"origin_server_ts": 1432735824651,
"unsigned": {
"age": 1234
}
}
]
}
)
"
_json
;
static
Event
event1
=
R
"
(
{
"type": "m.room.message",
"event_id": "$event1:example.org",
"room_id": "!foo:example.org",
"sender": "@example:example.org",
"origin_server_ts": 1432735824654
}
)
"
_json
;
static
Event
event2
=
R
"
(
{
"type": "m.room.message",
"event_id": "$event2:example.org",
"room_id": "!foo:example.org",
"sender": "@example:example.org",
"origin_server_ts": 1432735824656
}
)
"
_json
;
static
Event
secEvent
=
R
"
(
{
"content": {
"name": "The room name"
},
"type": "m.room.name",
"event_id": "$second:example.org",
"room_id": "!foo:example.org",
"sender": "@example:example.org",
"origin_server_ts": 1432735824653,
"unsigned": {
"age": 1234
},
"state_key": ""
}
)
"
_json
;
TEST_CASE
(
"Sending paginate job"
,
"[client][paginate]"
)
{
ClientModel
loggedInModel
=
makeClient
(
withRoom
(
makeRoom
(
withRoomId
(
"!foo:example.com"
)
|
withRoomTimelineGaps
({{
"$event"
,
"some-opaque-token"
}})
))
);
auto
[
resModel
,
dontCareEffect
]
=
ClientModel
::
update
(
loggedInModel
,
PaginateTimelineAction
{
"!foo:example.com"
,
"$event"
,
std
::
nullopt
});
assert1Job
(
resModel
);
for1stJob
(
resModel
,
[]
(
const
auto
&
job
)
{
REQUIRE
(
job
.
jobId
()
==
"GetRoomEvents"
);
REQUIRE_THAT
(
job
.
url
(),
ContainsSubstring
(
"/rooms/!foo:example.com/"
));
REQUIRE_THAT
(
job
.
requestQuery
(),
Contains
(
std
::
make_pair
(
"dir"
s
,
"b"
s
)));
REQUIRE_THAT
(
job
.
requestQuery
(),
Contains
(
std
::
make_pair
(
"from"
s
,
"some-opaque-token"
s
)));
});
}
TEST_CASE
(
"Pagination should remove the original gap and record a new one"
,
"[client][paginate]"
)
{
using
namespace
Kazv
::
CursorOp
;
boost
::
asio
::
io_context
io
;
AsioPromiseHandler
ph
{
io
.
get_executor
()};
ClientModel
m
=
makeClient
(
withRoom
(
makeRoom
(
withRoomId
(
"!foo:example.org"
)
|
withRoomTimeline
({
event1
,
event2
})
|
withRoomTimelineGaps
({{
event1
.
id
(),
"prevBatchForEvent1"
}})
))
);
auto
store
=
createTestClientStoreFrom
(
m
,
ph
);
auto
resp
=
makeResponse
(
"GetRoomEvents"
,
withResponseJsonBody
(
paginateResponseJson
)
|
withResponseDataKV
(
"roomId"
,
"!foo:example.org"
)
|
withResponseDataKV
(
"gapEventId"
,
"$event1:example.org"
)
);
auto
client
=
Client
(
store
.
reader
().
map
([](
auto
c
)
{
return
SdkModel
{
c
};
}),
store
,
std
::
nullopt
);
store
.
dispatch
(
ProcessResponseAction
{
resp
});
io
.
run
();
auto
r
=
client
.
room
(
"!foo:example.org"
);
auto
timelineGaps
=
+
r
.
timelineGaps
();
REQUIRE
(
!
timelineGaps
.
find
(
"$event1:example.org"
));
REQUIRE
(
timelineGaps
.
at
(
"$first:example.org"
)
==
"anotherPrevBatch"
);
}
TEST_CASE
(
"Pagination should erase all gaps in (start-of-fetched-batch, orig-gapped-event]"
,
"[client][paginate]"
)
{
using
namespace
Kazv
::
CursorOp
;
boost
::
asio
::
io_context
io
;
AsioPromiseHandler
ph
{
io
.
get_executor
()};
ClientModel
m
=
makeClient
(
withRoom
(
makeRoom
(
withRoomId
(
"!foo:example.org"
)
|
withRoomTimeline
({
event1
,
event2
,
secEvent
})
|
withRoomTimelineGaps
({
{
event1
.
id
(),
"prevBatchForEvent1"
},
{
secEvent
.
id
(),
"prevBatchForSecEvent"
},
})
))
);
auto
store
=
createTestClientStoreFrom
(
m
,
ph
);
auto
resp
=
makeResponse
(
"GetRoomEvents"
,
withResponseJsonBody
(
paginateResponseJson
)
|
withResponseDataKV
(
"roomId"
,
"!foo:example.org"
)
|
withResponseDataKV
(
"gapEventId"
,
"$event1:example.org"
)
);
auto
client
=
Client
(
store
.
reader
().
map
([](
auto
c
)
{
return
SdkModel
{
c
};
}),
store
,
std
::
nullopt
);
store
.
dispatch
(
ProcessResponseAction
{
resp
});
io
.
run
();
auto
r
=
client
.
room
(
"!foo:example.org"
);
auto
timelineGaps
=
+
r
.
timelineGaps
();
REQUIRE
(
!
timelineGaps
.
find
(
"$second:example.org"
));
REQUIRE
(
timelineGaps
.
at
(
"$first:example.org"
)
==
"anotherPrevBatch"
);
}
TEST_CASE
(
"Pagination should not crash if returned chunk's first event is the gapped event"
,
"[client][paginate]"
)
{
using
namespace
Kazv
::
CursorOp
;
boost
::
asio
::
io_context
io
;
AsioPromiseHandler
ph
{
io
.
get_executor
()};
ClientModel
m
=
makeClient
(
withRoom
(
makeRoom
(
withRoomId
(
"!foo:example.org"
)
|
withRoomTimeline
({
event1
,
event2
})
|
withRoomTimelineGaps
({{
event1
.
id
(),
"prevBatchForEvent1"
}})
))
);
auto
store
=
createTestClientStoreFrom
(
m
,
ph
);
auto
paginateRespWithEvent1
=
paginateResponseJson
;
paginateRespWithEvent1
[
"chunk"
]
=
json
::
array
({
event1
.
raw
().
get
()});
auto
resp
=
makeResponse
(
"GetRoomEvents"
,
withResponseJsonBody
(
paginateRespWithEvent1
)
|
withResponseDataKV
(
"roomId"
,
"!foo:example.org"
)
|
withResponseDataKV
(
"gapEventId"
,
"$event1:example.org"
)
);
store
.
dispatch
(
ProcessResponseAction
{
resp
});
io
.
run
();
auto
client
=
Client
(
store
.
reader
().
map
([](
auto
c
)
{
return
SdkModel
{
c
};
}),
store
,
std
::
nullopt
);
auto
r
=
client
.
room
(
"!foo:example.org"
);
auto
timelineGaps
=
+
r
.
timelineGaps
();
REQUIRE
(
!
timelineGaps
.
find
(
"$event1:example.org"
));
}
File Metadata
Details
Attached
Mime Type
text/x-c
Expires
Thu, Oct 2, 4:27 AM (15 h, 9 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
471711
Default Alt Text
paginate-test.cpp (7 KB)
Attached To
Mode
rL libkazv
Attached
Detach File
Event Timeline
Log In to Comment