2021-04-06 14:21:02 +03:00
# Copyright 2018-2021 The Matrix.org Foundation C.I.C.
2018-07-19 22:19:32 +03:00
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
2018-07-19 22:49:44 +03:00
import logging
2021-09-14 18:35:53 +03:00
from frozendict import frozendict
2019-04-01 12:24:38 +03:00
from synapse . api . constants import EventTypes , Membership
from synapse . api . room_versions import RoomVersions
2018-10-25 19:49:55 +03:00
from synapse . storage . state import StateFilter
2018-07-19 22:19:32 +03:00
from synapse . types import RoomID , UserID
2021-10-12 12:44:59 +03:00
from tests . unittest import HomeserverTestCase , TestCase
2018-07-19 22:19:32 +03:00
2018-07-19 22:49:44 +03:00
logger = logging . getLogger ( __name__ )
2018-07-19 22:19:32 +03:00
2021-04-06 14:21:02 +03:00
class StateStoreTestCase ( HomeserverTestCase ) :
def prepare ( self , reactor , clock , hs ) :
2022-02-23 14:04:02 +03:00
self . store = hs . get_datastores ( ) . main
2022-05-31 15:17:50 +03:00
self . storage = hs . get_storage_controllers ( )
2019-12-20 13:48:24 +03:00
self . state_datastore = self . storage . state . stores . state
2018-07-19 22:19:32 +03:00
self . event_builder_factory = hs . get_event_builder_factory ( )
self . event_creation_handler = hs . get_event_creation_handler ( )
self . u_alice = UserID . from_string ( " @alice:test " )
self . u_bob = UserID . from_string ( " @bob:test " )
self . room = RoomID . from_string ( " !abc123:test " )
2021-04-06 14:21:02 +03:00
self . get_success (
2020-07-30 14:20:41 +03:00
self . store . store_room (
self . room . to_string ( ) ,
room_creator_user_id = " @creator:text " ,
is_public = True ,
room_version = RoomVersions . V1 ,
)
2018-07-19 22:19:32 +03:00
)
def inject_state_event ( self , room , sender , typ , state_key , content ) :
2019-04-01 12:24:38 +03:00
builder = self . event_builder_factory . for_room_version (
2019-01-24 12:28:16 +03:00
RoomVersions . V1 ,
2018-08-10 16:54:09 +03:00
{
" type " : typ ,
" sender " : sender . to_string ( ) ,
" state_key " : state_key ,
" room_id " : room . to_string ( ) ,
" content " : content ,
2019-05-10 08:12:11 +03:00
} ,
2018-08-10 16:54:09 +03:00
)
2018-07-19 22:19:32 +03:00
2021-04-06 14:21:02 +03:00
event , context = self . get_success (
2020-07-22 19:29:15 +03:00
self . event_creation_handler . create_new_client_event ( builder )
2018-07-19 22:19:32 +03:00
)
2021-04-06 14:21:02 +03:00
self . get_success ( self . storage . persistence . persist_event ( event , context ) )
2018-07-19 22:19:32 +03:00
2019-07-23 16:00:55 +03:00
return event
2018-07-19 22:19:32 +03:00
2018-07-19 22:49:44 +03:00
def assertStateMapEqual ( self , s1 , s2 ) :
for t in s1 :
# just compare event IDs for simplicity
self . assertEqual ( s1 [ t ] . event_id , s2 [ t ] . event_id )
self . assertEqual ( len ( s1 ) , len ( s2 ) )
2018-09-27 13:22:25 +03:00
def test_get_state_groups_ids ( self ) :
2021-04-06 14:21:02 +03:00
e1 = self . inject_state_event ( self . room , self . u_alice , EventTypes . Create , " " , { } )
e2 = self . inject_state_event (
2019-06-20 12:32:02 +03:00
self . room , self . u_alice , EventTypes . Name , " " , { " name " : " test room " }
2018-09-27 13:22:25 +03:00
)
2021-04-06 14:21:02 +03:00
state_group_map = self . get_success (
2020-07-28 23:09:53 +03:00
self . storage . state . get_state_groups_ids ( self . room , [ e2 . event_id ] )
2019-05-10 08:12:11 +03:00
)
2018-09-27 13:22:25 +03:00
self . assertEqual ( len ( state_group_map ) , 1 )
state_map = list ( state_group_map . values ( ) ) [ 0 ]
self . assertDictEqual (
state_map ,
2019-06-20 12:32:02 +03:00
{ ( EventTypes . Create , " " ) : e1 . event_id , ( EventTypes . Name , " " ) : e2 . event_id } ,
2018-09-27 13:22:25 +03:00
)
def test_get_state_groups ( self ) :
2021-04-06 14:21:02 +03:00
e1 = self . inject_state_event ( self . room , self . u_alice , EventTypes . Create , " " , { } )
e2 = self . inject_state_event (
2019-06-20 12:32:02 +03:00
self . room , self . u_alice , EventTypes . Name , " " , { " name " : " test room " }
2018-09-27 13:22:25 +03:00
)
2021-04-06 14:21:02 +03:00
state_group_map = self . get_success (
2020-07-28 23:09:53 +03:00
self . storage . state . get_state_groups ( self . room , [ e2 . event_id ] )
2019-10-23 19:25:54 +03:00
)
2018-09-27 13:22:25 +03:00
self . assertEqual ( len ( state_group_map ) , 1 )
state_list = list ( state_group_map . values ( ) ) [ 0 ]
2019-05-10 08:12:11 +03:00
self . assertEqual ( { ev . event_id for ev in state_list } , { e1 . event_id , e2 . event_id } )
2018-09-27 13:22:25 +03:00
2018-07-19 22:49:44 +03:00
def test_get_state_for_event ( self ) :
2018-07-19 22:19:32 +03:00
# this defaults to a linear DAG as each new injection defaults to whatever
# forward extremities are currently in the DB for this room.
2021-04-06 14:21:02 +03:00
e1 = self . inject_state_event ( self . room , self . u_alice , EventTypes . Create , " " , { } )
e2 = self . inject_state_event (
2019-06-20 12:32:02 +03:00
self . room , self . u_alice , EventTypes . Name , " " , { " name " : " test room " }
2018-07-19 22:19:32 +03:00
)
2021-04-06 14:21:02 +03:00
e3 = self . inject_state_event (
2018-08-10 16:54:09 +03:00
self . room ,
self . u_alice ,
EventTypes . Member ,
self . u_alice . to_string ( ) ,
{ " membership " : Membership . JOIN } ,
2018-07-19 22:19:32 +03:00
)
2021-04-06 14:21:02 +03:00
e4 = self . inject_state_event (
2018-08-10 16:54:09 +03:00
self . room ,
self . u_bob ,
EventTypes . Member ,
self . u_bob . to_string ( ) ,
{ " membership " : Membership . JOIN } ,
2018-07-19 22:19:32 +03:00
)
2021-04-06 14:21:02 +03:00
e5 = self . inject_state_event (
2018-08-10 16:54:09 +03:00
self . room ,
self . u_bob ,
EventTypes . Member ,
self . u_bob . to_string ( ) ,
{ " membership " : Membership . LEAVE } ,
2018-07-19 22:19:32 +03:00
)
# check we get the full state as of the final event
2021-04-06 14:21:02 +03:00
state = self . get_success ( self . storage . state . get_state_for_event ( e5 . event_id ) )
2018-07-19 22:19:32 +03:00
2018-07-19 22:49:44 +03:00
self . assertIsNotNone ( e4 )
2018-08-10 16:54:09 +03:00
self . assertStateMapEqual (
{
( e1 . type , e1 . state_key ) : e1 ,
( e2 . type , e2 . state_key ) : e2 ,
( e3 . type , e3 . state_key ) : e3 ,
# e4 is overwritten by e5
( e5 . type , e5 . state_key ) : e5 ,
} ,
state ,
)
2018-07-19 22:19:32 +03:00
# check we can filter to the m.room.name event (with a '' state key)
2021-04-06 14:21:02 +03:00
state = self . get_success (
2020-07-28 23:09:53 +03:00
self . storage . state . get_state_for_event (
e5 . event_id , StateFilter . from_types ( [ ( EventTypes . Name , " " ) ] )
)
2018-07-19 22:19:32 +03:00
)
2018-08-10 16:54:09 +03:00
self . assertStateMapEqual ( { ( e2 . type , e2 . state_key ) : e2 } , state )
2018-07-19 22:19:32 +03:00
# check we can filter to the m.room.name event (with a wildcard None state key)
2021-04-06 14:21:02 +03:00
state = self . get_success (
2020-07-28 23:09:53 +03:00
self . storage . state . get_state_for_event (
e5 . event_id , StateFilter . from_types ( [ ( EventTypes . Name , None ) ] )
)
2018-07-19 22:19:32 +03:00
)
2018-08-10 16:54:09 +03:00
self . assertStateMapEqual ( { ( e2 . type , e2 . state_key ) : e2 } , state )
2018-07-19 22:19:32 +03:00
# check we can grab the m.room.member events (with a wildcard None state key)
2021-04-06 14:21:02 +03:00
state = self . get_success (
2020-07-28 23:09:53 +03:00
self . storage . state . get_state_for_event (
e5 . event_id , StateFilter . from_types ( [ ( EventTypes . Member , None ) ] )
)
2018-07-19 22:19:32 +03:00
)
2018-08-10 16:54:09 +03:00
self . assertStateMapEqual (
{ ( e3 . type , e3 . state_key ) : e3 , ( e5 . type , e5 . state_key ) : e5 } , state
)
2018-07-19 22:19:32 +03:00
2018-10-25 19:49:55 +03:00
# check we can grab a specific room member without filtering out the
# other event types
2021-04-06 14:21:02 +03:00
state = self . get_success (
2020-07-28 23:09:53 +03:00
self . storage . state . get_state_for_event (
e5 . event_id ,
state_filter = StateFilter (
2021-09-14 18:35:53 +03:00
types = frozendict (
{ EventTypes . Member : frozenset ( { self . u_alice . to_string ( ) } ) }
) ,
2020-07-28 23:09:53 +03:00
include_others = True ,
) ,
)
2018-07-19 22:19:32 +03:00
)
2018-08-10 16:54:09 +03:00
self . assertStateMapEqual (
{
( e1 . type , e1 . state_key ) : e1 ,
( e2 . type , e2 . state_key ) : e2 ,
( e3 . type , e3 . state_key ) : e3 ,
} ,
state ,
)
2018-07-24 14:39:40 +03:00
2018-10-25 19:49:55 +03:00
# check that we can grab everything except members
2021-04-06 14:21:02 +03:00
state = self . get_success (
2020-07-28 23:09:53 +03:00
self . storage . state . get_state_for_event (
e5 . event_id ,
state_filter = StateFilter (
2021-09-14 18:35:53 +03:00
types = frozendict ( { EventTypes . Member : frozenset ( ) } ) ,
include_others = True ,
2020-07-28 23:09:53 +03:00
) ,
)
2018-07-24 14:39:40 +03:00
)
2018-08-10 16:54:09 +03:00
self . assertStateMapEqual (
{ ( e1 . type , e1 . state_key ) : e1 , ( e2 . type , e2 . state_key ) : e2 } , state
)
2018-07-25 18:10:34 +03:00
2018-07-25 19:21:17 +03:00
#######################################################
2018-10-25 19:49:55 +03:00
# _get_state_for_group_using_cache tests against a full cache
2018-07-25 19:21:17 +03:00
#######################################################
2018-07-25 18:10:34 +03:00
room_id = self . room . to_string ( )
2021-04-06 14:21:02 +03:00
group_ids = self . get_success (
2020-07-28 23:09:53 +03:00
self . storage . state . get_state_groups_ids ( room_id , [ e5 . event_id ] )
2019-10-23 19:25:54 +03:00
)
2018-08-09 05:22:01 +03:00
group = list ( group_ids . keys ( ) ) [ 0 ]
2018-07-25 18:10:34 +03:00
2018-10-25 19:49:55 +03:00
# test _get_state_for_group_using_cache correctly filters out members
# with types=[]
2021-04-06 14:21:02 +03:00
( state_dict , is_all , ) = self . state_datastore . _get_state_for_group_using_cache (
2019-10-23 19:25:54 +03:00
self . state_datastore . _state_group_cache ,
2019-05-10 08:12:11 +03:00
group ,
2018-10-25 19:49:55 +03:00
state_filter = StateFilter (
2021-09-14 18:35:53 +03:00
types = frozendict ( { EventTypes . Member : frozenset ( ) } ) , include_others = True
2018-10-25 19:49:55 +03:00
) ,
2018-07-25 18:10:34 +03:00
)
self . assertEqual ( is_all , True )
2018-08-10 16:54:09 +03:00
self . assertDictEqual (
{
( e1 . type , e1 . state_key ) : e1 . event_id ,
( e2 . type , e2 . state_key ) : e2 . event_id ,
} ,
state_dict ,
)
2018-07-25 18:10:34 +03:00
2021-04-06 14:21:02 +03:00
( state_dict , is_all , ) = self . state_datastore . _get_state_for_group_using_cache (
2019-10-23 19:25:54 +03:00
self . state_datastore . _state_group_members_cache ,
2018-09-06 19:58:18 +03:00
group ,
2018-10-25 19:49:55 +03:00
state_filter = StateFilter (
2021-09-14 18:35:53 +03:00
types = frozendict ( { EventTypes . Member : frozenset ( ) } ) , include_others = True
2018-10-25 19:49:55 +03:00
) ,
2018-08-22 01:56:37 +03:00
)
self . assertEqual ( is_all , True )
2018-09-06 19:58:18 +03:00
self . assertDictEqual ( { } , state_dict )
2018-08-22 01:56:37 +03:00
2018-10-25 19:49:55 +03:00
# test _get_state_for_group_using_cache correctly filters in members
# with wildcard types
2021-04-06 14:21:02 +03:00
( state_dict , is_all , ) = self . state_datastore . _get_state_for_group_using_cache (
2019-10-23 19:25:54 +03:00
self . state_datastore . _state_group_cache ,
2018-09-06 19:58:18 +03:00
group ,
2018-10-25 19:49:55 +03:00
state_filter = StateFilter (
2021-09-14 18:35:53 +03:00
types = frozendict ( { EventTypes . Member : None } ) , include_others = True
2018-10-25 19:49:55 +03:00
) ,
2018-07-25 18:10:34 +03:00
)
self . assertEqual ( is_all , True )
2018-08-10 16:54:09 +03:00
self . assertDictEqual (
{
( e1 . type , e1 . state_key ) : e1 . event_id ,
( e2 . type , e2 . state_key ) : e2 . event_id ,
2018-08-22 01:56:37 +03:00
} ,
state_dict ,
)
2021-04-06 14:21:02 +03:00
( state_dict , is_all , ) = self . state_datastore . _get_state_for_group_using_cache (
2019-10-23 19:25:54 +03:00
self . state_datastore . _state_group_members_cache ,
2018-09-06 19:58:18 +03:00
group ,
2018-10-25 19:49:55 +03:00
state_filter = StateFilter (
2021-09-14 18:35:53 +03:00
types = frozendict ( { EventTypes . Member : None } ) , include_others = True
2018-10-25 19:49:55 +03:00
) ,
2018-08-22 01:56:37 +03:00
)
self . assertEqual ( is_all , True )
self . assertDictEqual (
{
2018-08-10 16:54:09 +03:00
( e3 . type , e3 . state_key ) : e3 . event_id ,
# e4 is overwritten by e5
( e5 . type , e5 . state_key ) : e5 . event_id ,
} ,
state_dict ,
)
2018-07-25 18:10:34 +03:00
2018-10-25 19:49:55 +03:00
# test _get_state_for_group_using_cache correctly filters in members
# with specific types
2021-04-06 14:21:02 +03:00
( state_dict , is_all , ) = self . state_datastore . _get_state_for_group_using_cache (
2019-10-23 19:25:54 +03:00
self . state_datastore . _state_group_cache ,
2018-08-10 16:54:09 +03:00
group ,
2018-10-25 19:49:55 +03:00
state_filter = StateFilter (
2021-09-14 18:35:53 +03:00
types = frozendict ( { EventTypes . Member : frozenset ( { e5 . state_key } ) } ) ,
include_others = True ,
2018-10-25 19:49:55 +03:00
) ,
2018-07-25 18:10:34 +03:00
)
self . assertEqual ( is_all , True )
2018-08-10 16:54:09 +03:00
self . assertDictEqual (
{
( e1 . type , e1 . state_key ) : e1 . event_id ,
( e2 . type , e2 . state_key ) : e2 . event_id ,
2018-08-22 01:56:37 +03:00
} ,
state_dict ,
)
2021-04-06 14:21:02 +03:00
( state_dict , is_all , ) = self . state_datastore . _get_state_for_group_using_cache (
2019-10-23 19:25:54 +03:00
self . state_datastore . _state_group_members_cache ,
2018-08-22 01:56:37 +03:00
group ,
2018-10-25 19:49:55 +03:00
state_filter = StateFilter (
2021-09-14 18:35:53 +03:00
types = frozendict ( { EventTypes . Member : frozenset ( { e5 . state_key } ) } ) ,
include_others = True ,
2018-10-25 19:49:55 +03:00
) ,
2018-08-22 01:56:37 +03:00
)
self . assertEqual ( is_all , True )
2018-09-06 19:58:18 +03:00
self . assertDictEqual ( { ( e5 . type , e5 . state_key ) : e5 . event_id } , state_dict )
2018-07-25 18:10:34 +03:00
2018-10-25 19:49:55 +03:00
# test _get_state_for_group_using_cache correctly filters in members
# with specific types
2021-04-06 14:21:02 +03:00
( state_dict , is_all , ) = self . state_datastore . _get_state_for_group_using_cache (
2019-10-23 19:25:54 +03:00
self . state_datastore . _state_group_members_cache ,
2018-09-06 19:58:18 +03:00
group ,
2018-10-25 19:49:55 +03:00
state_filter = StateFilter (
2021-09-14 18:35:53 +03:00
types = frozendict ( { EventTypes . Member : frozenset ( { e5 . state_key } ) } ) ,
include_others = False ,
2018-10-25 19:49:55 +03:00
) ,
2018-07-25 18:10:34 +03:00
)
self . assertEqual ( is_all , True )
2018-08-10 16:54:09 +03:00
self . assertDictEqual ( { ( e5 . type , e5 . state_key ) : e5 . event_id } , state_dict )
2018-07-25 18:10:34 +03:00
#######################################################
# deliberately remove e2 (room name) from the _state_group_cache
2021-03-29 19:15:33 +03:00
cache_entry = self . state_datastore . _state_group_cache . get ( group )
state_dict_ids = cache_entry . value
2018-07-25 18:10:34 +03:00
2021-03-29 19:15:33 +03:00
self . assertEqual ( cache_entry . full , True )
self . assertEqual ( cache_entry . known_absent , set ( ) )
2018-08-10 16:54:09 +03:00
self . assertDictEqual (
state_dict_ids ,
{
( e1 . type , e1 . state_key ) : e1 . event_id ,
( e2 . type , e2 . state_key ) : e2 . event_id ,
} ,
)
2018-07-25 18:10:34 +03:00
state_dict_ids . pop ( ( e2 . type , e2 . state_key ) )
2019-10-23 19:25:54 +03:00
self . state_datastore . _state_group_cache . invalidate ( group )
self . state_datastore . _state_group_cache . update (
sequence = self . state_datastore . _state_group_cache . sequence ,
2018-07-25 18:10:34 +03:00
key = group ,
value = state_dict_ids ,
# list fetched keys so it knows it's partial
2018-09-06 19:58:18 +03:00
fetched_keys = ( ( e1 . type , e1 . state_key ) , ) ,
2018-07-25 18:10:34 +03:00
)
2021-03-29 19:15:33 +03:00
cache_entry = self . state_datastore . _state_group_cache . get ( group )
state_dict_ids = cache_entry . value
2018-07-25 18:10:34 +03:00
2021-03-29 19:15:33 +03:00
self . assertEqual ( cache_entry . full , False )
2022-07-21 19:13:44 +03:00
self . assertEqual ( cache_entry . known_absent , set ( ) )
self . assertDictEqual ( state_dict_ids , { } )
2018-07-25 18:10:34 +03:00
2018-07-25 19:21:17 +03:00
############################################
2018-07-25 18:10:34 +03:00
# test that things work with a partial cache
2018-10-25 19:49:55 +03:00
# test _get_state_for_group_using_cache correctly filters out members
# with types=[]
2018-07-25 18:10:34 +03:00
room_id = self . room . to_string ( )
2021-04-06 14:21:02 +03:00
( state_dict , is_all , ) = self . state_datastore . _get_state_for_group_using_cache (
2019-10-23 19:25:54 +03:00
self . state_datastore . _state_group_cache ,
2019-05-10 08:12:11 +03:00
group ,
2018-10-25 19:49:55 +03:00
state_filter = StateFilter (
2021-09-14 18:35:53 +03:00
types = frozendict ( { EventTypes . Member : frozenset ( ) } ) , include_others = True
2018-10-25 19:49:55 +03:00
) ,
2018-07-25 18:10:34 +03:00
)
self . assertEqual ( is_all , False )
2022-07-21 19:13:44 +03:00
self . assertDictEqual ( { } , state_dict )
2018-07-25 18:10:34 +03:00
2018-08-22 01:56:37 +03:00
room_id = self . room . to_string ( )
2021-04-06 14:21:02 +03:00
( state_dict , is_all , ) = self . state_datastore . _get_state_for_group_using_cache (
2019-10-23 19:25:54 +03:00
self . state_datastore . _state_group_members_cache ,
2018-09-06 19:58:18 +03:00
group ,
2018-10-25 19:49:55 +03:00
state_filter = StateFilter (
2021-09-14 18:35:53 +03:00
types = frozendict ( { EventTypes . Member : frozenset ( ) } ) , include_others = True
2018-10-25 19:49:55 +03:00
) ,
2018-08-22 01:56:37 +03:00
)
self . assertEqual ( is_all , True )
self . assertDictEqual ( { } , state_dict )
2018-10-25 19:49:55 +03:00
# test _get_state_for_group_using_cache correctly filters in members
# wildcard types
2021-04-06 14:21:02 +03:00
( state_dict , is_all , ) = self . state_datastore . _get_state_for_group_using_cache (
2019-10-23 19:25:54 +03:00
self . state_datastore . _state_group_cache ,
2018-09-06 19:58:18 +03:00
group ,
2018-10-25 19:49:55 +03:00
state_filter = StateFilter (
2021-09-14 18:35:53 +03:00
types = frozendict ( { EventTypes . Member : None } ) , include_others = True
2018-10-25 19:49:55 +03:00
) ,
2018-07-25 18:10:34 +03:00
)
self . assertEqual ( is_all , False )
2022-07-21 19:13:44 +03:00
self . assertDictEqual ( { } , state_dict )
2018-08-22 01:56:37 +03:00
2021-04-06 14:21:02 +03:00
( state_dict , is_all , ) = self . state_datastore . _get_state_for_group_using_cache (
2019-10-23 19:25:54 +03:00
self . state_datastore . _state_group_members_cache ,
2018-09-06 19:58:18 +03:00
group ,
2018-10-25 19:49:55 +03:00
state_filter = StateFilter (
2021-09-14 18:35:53 +03:00
types = frozendict ( { EventTypes . Member : None } ) , include_others = True
2018-10-25 19:49:55 +03:00
) ,
2018-08-22 01:56:37 +03:00
)
self . assertEqual ( is_all , True )
self . assertDictEqual (
{
2018-08-10 16:54:09 +03:00
( e3 . type , e3 . state_key ) : e3 . event_id ,
( e5 . type , e5 . state_key ) : e5 . event_id ,
} ,
state_dict ,
)
2018-07-25 18:10:34 +03:00
2018-10-25 19:49:55 +03:00
# test _get_state_for_group_using_cache correctly filters in members
# with specific types
2021-04-06 14:21:02 +03:00
( state_dict , is_all , ) = self . state_datastore . _get_state_for_group_using_cache (
2019-10-23 19:25:54 +03:00
self . state_datastore . _state_group_cache ,
2018-08-10 16:54:09 +03:00
group ,
2018-10-25 19:49:55 +03:00
state_filter = StateFilter (
2021-09-14 18:35:53 +03:00
types = frozendict ( { EventTypes . Member : frozenset ( { e5 . state_key } ) } ) ,
include_others = True ,
2018-10-25 19:49:55 +03:00
) ,
2018-07-25 18:10:34 +03:00
)
self . assertEqual ( is_all , False )
2022-07-21 19:13:44 +03:00
self . assertDictEqual ( { } , state_dict )
2018-08-22 01:56:37 +03:00
2021-04-06 14:21:02 +03:00
( state_dict , is_all , ) = self . state_datastore . _get_state_for_group_using_cache (
2019-10-23 19:25:54 +03:00
self . state_datastore . _state_group_members_cache ,
2018-08-22 01:56:37 +03:00
group ,
2018-10-25 19:49:55 +03:00
state_filter = StateFilter (
2021-09-14 18:35:53 +03:00
types = frozendict ( { EventTypes . Member : frozenset ( { e5 . state_key } ) } ) ,
include_others = True ,
2018-10-25 19:49:55 +03:00
) ,
2018-08-22 01:56:37 +03:00
)
self . assertEqual ( is_all , True )
2018-09-06 19:58:18 +03:00
self . assertDictEqual ( { ( e5 . type , e5 . state_key ) : e5 . event_id } , state_dict )
2018-07-25 18:10:34 +03:00
2018-10-25 19:49:55 +03:00
# test _get_state_for_group_using_cache correctly filters in members
# with specific types
2021-04-06 14:21:02 +03:00
( state_dict , is_all , ) = self . state_datastore . _get_state_for_group_using_cache (
2019-10-23 19:25:54 +03:00
self . state_datastore . _state_group_cache ,
2018-09-06 19:58:18 +03:00
group ,
2018-10-25 19:49:55 +03:00
state_filter = StateFilter (
2021-09-14 18:35:53 +03:00
types = frozendict ( { EventTypes . Member : frozenset ( { e5 . state_key } ) } ) ,
include_others = False ,
2018-10-25 19:49:55 +03:00
) ,
2018-08-22 01:56:37 +03:00
)
self . assertEqual ( is_all , False )
self . assertDictEqual ( { } , state_dict )
2021-04-06 14:21:02 +03:00
( state_dict , is_all , ) = self . state_datastore . _get_state_for_group_using_cache (
2019-10-23 19:25:54 +03:00
self . state_datastore . _state_group_members_cache ,
2018-09-06 19:58:18 +03:00
group ,
2018-10-25 19:49:55 +03:00
state_filter = StateFilter (
2021-09-14 18:35:53 +03:00
types = frozendict ( { EventTypes . Member : frozenset ( { e5 . state_key } ) } ) ,
include_others = False ,
2018-10-25 19:49:55 +03:00
) ,
2018-07-25 18:10:34 +03:00
)
self . assertEqual ( is_all , True )
2018-09-06 19:58:18 +03:00
self . assertDictEqual ( { ( e5 . type , e5 . state_key ) : e5 . event_id } , state_dict )
2021-10-12 12:44:59 +03:00
class StateFilterDifferenceTestCase ( TestCase ) :
def assert_difference (
self , minuend : StateFilter , subtrahend : StateFilter , expected : StateFilter
) :
self . assertEqual (
minuend . approx_difference ( subtrahend ) ,
expected ,
f " StateFilter difference not correct: \n \n \t { minuend !r} \n minus \n \t { subtrahend !r} \n was \n \t { minuend . approx_difference ( subtrahend ) } \n expected \n \t { expected } " ,
)
def test_state_filter_difference_no_include_other_minus_no_include_other ( self ) :
"""
Tests the StateFilter . approx_difference method
where , in a . approx_difference ( b ) , both a and b do not have the
include_others flag set .
"""
# (wildcard on state keys) - (wildcard on state keys):
self . assert_difference (
StateFilter . freeze (
{ EventTypes . Member : None , EventTypes . Create : None } ,
include_others = False ,
) ,
StateFilter . freeze (
{ EventTypes . Member : None , EventTypes . CanonicalAlias : None } ,
include_others = False ,
) ,
StateFilter . freeze ( { EventTypes . Create : None } , include_others = False ) ,
)
# (wildcard on state keys) - (specific state keys)
# This one is an over-approximation because we can't represent
# 'all state keys except a few named examples'
self . assert_difference (
StateFilter . freeze ( { EventTypes . Member : None } , include_others = False ) ,
StateFilter . freeze (
{ EventTypes . Member : { " @wombat:spqr " } } ,
include_others = False ,
) ,
StateFilter . freeze ( { EventTypes . Member : None } , include_others = False ) ,
)
# (wildcard on state keys) - (no state keys)
self . assert_difference (
StateFilter . freeze (
{ EventTypes . Member : None } ,
include_others = False ,
) ,
StateFilter . freeze (
{
EventTypes . Member : set ( ) ,
} ,
include_others = False ,
) ,
StateFilter . freeze (
{ EventTypes . Member : None } ,
include_others = False ,
) ,
)
# (specific state keys) - (wildcard on state keys):
self . assert_difference (
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " , " @spqr:spqr " } ,
EventTypes . CanonicalAlias : { " " } ,
} ,
include_others = False ,
) ,
StateFilter . freeze (
{ EventTypes . Member : None } ,
include_others = False ,
) ,
StateFilter . freeze (
{ EventTypes . CanonicalAlias : { " " } } ,
include_others = False ,
) ,
)
# (specific state keys) - (specific state keys)
self . assert_difference (
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " , " @spqr:spqr " } ,
EventTypes . CanonicalAlias : { " " } ,
} ,
include_others = False ,
) ,
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " } ,
} ,
include_others = False ,
) ,
StateFilter . freeze (
{
EventTypes . Member : { " @spqr:spqr " } ,
EventTypes . CanonicalAlias : { " " } ,
} ,
include_others = False ,
) ,
)
# (specific state keys) - (no state keys)
self . assert_difference (
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " , " @spqr:spqr " } ,
EventTypes . CanonicalAlias : { " " } ,
} ,
include_others = False ,
) ,
StateFilter . freeze (
{
EventTypes . Member : set ( ) ,
} ,
include_others = False ,
) ,
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " , " @spqr:spqr " } ,
EventTypes . CanonicalAlias : { " " } ,
} ,
include_others = False ,
) ,
)
def test_state_filter_difference_include_other_minus_no_include_other ( self ) :
"""
Tests the StateFilter . approx_difference method
where , in a . approx_difference ( b ) , only a has the include_others flag set .
"""
# (wildcard on state keys) - (wildcard on state keys):
self . assert_difference (
StateFilter . freeze (
{ EventTypes . Member : None , EventTypes . Create : None } ,
include_others = True ,
) ,
StateFilter . freeze (
{ EventTypes . Member : None , EventTypes . CanonicalAlias : None } ,
include_others = False ,
) ,
StateFilter . freeze (
{
EventTypes . Create : None ,
EventTypes . Member : set ( ) ,
EventTypes . CanonicalAlias : set ( ) ,
} ,
include_others = True ,
) ,
)
# (wildcard on state keys) - (specific state keys)
# This one is an over-approximation because we can't represent
# 'all state keys except a few named examples'
# This also shows that the resultant state filter is normalised.
self . assert_difference (
StateFilter . freeze ( { EventTypes . Member : None } , include_others = True ) ,
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " } ,
EventTypes . Create : { " " } ,
} ,
include_others = False ,
) ,
StateFilter ( types = frozendict ( ) , include_others = True ) ,
)
# (wildcard on state keys) - (no state keys)
self . assert_difference (
StateFilter . freeze (
{ EventTypes . Member : None } ,
include_others = True ,
) ,
StateFilter . freeze (
{
EventTypes . Member : set ( ) ,
} ,
include_others = False ,
) ,
StateFilter (
types = frozendict ( ) ,
include_others = True ,
) ,
)
# (specific state keys) - (wildcard on state keys):
self . assert_difference (
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " , " @spqr:spqr " } ,
EventTypes . CanonicalAlias : { " " } ,
} ,
include_others = True ,
) ,
StateFilter . freeze (
{ EventTypes . Member : None } ,
include_others = False ,
) ,
StateFilter . freeze (
{
EventTypes . CanonicalAlias : { " " } ,
EventTypes . Member : set ( ) ,
} ,
include_others = True ,
) ,
)
# (specific state keys) - (specific state keys)
self . assert_difference (
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " , " @spqr:spqr " } ,
EventTypes . CanonicalAlias : { " " } ,
} ,
include_others = True ,
) ,
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " } ,
} ,
include_others = False ,
) ,
StateFilter . freeze (
{
EventTypes . Member : { " @spqr:spqr " } ,
EventTypes . CanonicalAlias : { " " } ,
} ,
include_others = True ,
) ,
)
# (specific state keys) - (no state keys)
self . assert_difference (
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " , " @spqr:spqr " } ,
EventTypes . CanonicalAlias : { " " } ,
} ,
include_others = True ,
) ,
StateFilter . freeze (
{
EventTypes . Member : set ( ) ,
} ,
include_others = False ,
) ,
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " , " @spqr:spqr " } ,
EventTypes . CanonicalAlias : { " " } ,
} ,
include_others = True ,
) ,
)
def test_state_filter_difference_include_other_minus_include_other ( self ) :
"""
Tests the StateFilter . approx_difference method
where , in a . approx_difference ( b ) , both a and b have the include_others
flag set .
"""
# (wildcard on state keys) - (wildcard on state keys):
self . assert_difference (
StateFilter . freeze (
{ EventTypes . Member : None , EventTypes . Create : None } ,
include_others = True ,
) ,
StateFilter . freeze (
{ EventTypes . Member : None , EventTypes . CanonicalAlias : None } ,
include_others = True ,
) ,
StateFilter ( types = frozendict ( ) , include_others = False ) ,
)
# (wildcard on state keys) - (specific state keys)
# This one is an over-approximation because we can't represent
# 'all state keys except a few named examples'
self . assert_difference (
StateFilter . freeze ( { EventTypes . Member : None } , include_others = True ) ,
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " } ,
EventTypes . CanonicalAlias : { " " } ,
} ,
include_others = True ,
) ,
StateFilter . freeze (
{ EventTypes . Member : None , EventTypes . CanonicalAlias : None } ,
include_others = False ,
) ,
)
# (wildcard on state keys) - (no state keys)
self . assert_difference (
StateFilter . freeze (
{ EventTypes . Member : None } ,
include_others = True ,
) ,
StateFilter . freeze (
{
EventTypes . Member : set ( ) ,
} ,
include_others = True ,
) ,
StateFilter . freeze (
{ EventTypes . Member : None } ,
include_others = False ,
) ,
)
# (specific state keys) - (wildcard on state keys):
self . assert_difference (
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " , " @spqr:spqr " } ,
EventTypes . CanonicalAlias : { " " } ,
} ,
include_others = True ,
) ,
StateFilter . freeze (
{ EventTypes . Member : None } ,
include_others = True ,
) ,
StateFilter (
types = frozendict ( ) ,
include_others = False ,
) ,
)
# (specific state keys) - (specific state keys)
# This one is an over-approximation because we can't represent
# 'all state keys except a few named examples'
self . assert_difference (
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " , " @spqr:spqr " } ,
EventTypes . CanonicalAlias : { " " } ,
EventTypes . Create : { " " } ,
} ,
include_others = True ,
) ,
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " } ,
EventTypes . Create : set ( ) ,
} ,
include_others = True ,
) ,
StateFilter . freeze (
{
EventTypes . Member : { " @spqr:spqr " } ,
EventTypes . Create : { " " } ,
} ,
include_others = False ,
) ,
)
# (specific state keys) - (no state keys)
self . assert_difference (
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " , " @spqr:spqr " } ,
EventTypes . CanonicalAlias : { " " } ,
} ,
include_others = True ,
) ,
StateFilter . freeze (
{
EventTypes . Member : set ( ) ,
} ,
include_others = True ,
) ,
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " , " @spqr:spqr " } ,
} ,
include_others = False ,
) ,
)
def test_state_filter_difference_no_include_other_minus_include_other ( self ) :
"""
Tests the StateFilter . approx_difference method
where , in a . approx_difference ( b ) , only b has the include_others flag set .
"""
# (wildcard on state keys) - (wildcard on state keys):
self . assert_difference (
StateFilter . freeze (
{ EventTypes . Member : None , EventTypes . Create : None } ,
include_others = False ,
) ,
StateFilter . freeze (
{ EventTypes . Member : None , EventTypes . CanonicalAlias : None } ,
include_others = True ,
) ,
StateFilter ( types = frozendict ( ) , include_others = False ) ,
)
# (wildcard on state keys) - (specific state keys)
# This one is an over-approximation because we can't represent
# 'all state keys except a few named examples'
self . assert_difference (
StateFilter . freeze ( { EventTypes . Member : None } , include_others = False ) ,
StateFilter . freeze (
{ EventTypes . Member : { " @wombat:spqr " } } ,
include_others = True ,
) ,
StateFilter . freeze ( { EventTypes . Member : None } , include_others = False ) ,
)
# (wildcard on state keys) - (no state keys)
self . assert_difference (
StateFilter . freeze (
{ EventTypes . Member : None } ,
include_others = False ,
) ,
StateFilter . freeze (
{
EventTypes . Member : set ( ) ,
} ,
include_others = True ,
) ,
StateFilter . freeze (
{ EventTypes . Member : None } ,
include_others = False ,
) ,
)
# (specific state keys) - (wildcard on state keys):
self . assert_difference (
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " , " @spqr:spqr " } ,
EventTypes . CanonicalAlias : { " " } ,
} ,
include_others = False ,
) ,
StateFilter . freeze (
{ EventTypes . Member : None } ,
include_others = True ,
) ,
StateFilter (
types = frozendict ( ) ,
include_others = False ,
) ,
)
# (specific state keys) - (specific state keys)
# This one is an over-approximation because we can't represent
# 'all state keys except a few named examples'
self . assert_difference (
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " , " @spqr:spqr " } ,
EventTypes . CanonicalAlias : { " " } ,
} ,
include_others = False ,
) ,
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " } ,
} ,
include_others = True ,
) ,
StateFilter . freeze (
{
EventTypes . Member : { " @spqr:spqr " } ,
} ,
include_others = False ,
) ,
)
# (specific state keys) - (no state keys)
self . assert_difference (
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " , " @spqr:spqr " } ,
EventTypes . CanonicalAlias : { " " } ,
} ,
include_others = False ,
) ,
StateFilter . freeze (
{
EventTypes . Member : set ( ) ,
} ,
include_others = True ,
) ,
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:spqr " , " @spqr:spqr " } ,
} ,
include_others = False ,
) ,
)
def test_state_filter_difference_simple_cases ( self ) :
"""
Tests some very simple cases of the StateFilter approx_difference ,
that are not explicitly tested by the more in - depth tests .
"""
self . assert_difference ( StateFilter . all ( ) , StateFilter . all ( ) , StateFilter . none ( ) )
self . assert_difference (
StateFilter . all ( ) ,
StateFilter . none ( ) ,
StateFilter . all ( ) ,
)
2022-02-18 17:54:31 +03:00
class StateFilterTestCase ( TestCase ) :
def test_return_expanded ( self ) :
"""
Tests the behaviour of the return_expanded ( ) function that expands
StateFilters to include more state types ( for the sake of cache hit rate ) .
"""
self . assertEqual ( StateFilter . all ( ) . return_expanded ( ) , StateFilter . all ( ) )
self . assertEqual ( StateFilter . none ( ) . return_expanded ( ) , StateFilter . none ( ) )
# Concrete-only state filters stay the same
# (Case: mixed filter)
self . assertEqual (
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:test " , " @alicia:test " } ,
" some.other.state.type " : { " " } ,
} ,
include_others = False ,
) . return_expanded ( ) ,
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:test " , " @alicia:test " } ,
" some.other.state.type " : { " " } ,
} ,
include_others = False ,
) ,
)
# Concrete-only state filters stay the same
# (Case: non-member-only filter)
self . assertEqual (
StateFilter . freeze (
{ " some.other.state.type " : { " " } } , include_others = False
) . return_expanded ( ) ,
StateFilter . freeze ( { " some.other.state.type " : { " " } } , include_others = False ) ,
)
# Concrete-only state filters stay the same
# (Case: member-only filter)
self . assertEqual (
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:test " , " @alicia:test " } ,
} ,
include_others = False ,
) . return_expanded ( ) ,
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:test " , " @alicia:test " } ,
} ,
include_others = False ,
) ,
)
# Wildcard member-only state filters stay the same
self . assertEqual (
StateFilter . freeze (
{ EventTypes . Member : None } ,
include_others = False ,
) . return_expanded ( ) ,
StateFilter . freeze (
{ EventTypes . Member : None } ,
include_others = False ,
) ,
)
# If there is a wildcard in the non-member portion of the filter,
# it's expanded to include ALL non-member events.
# (Case: mixed filter)
self . assertEqual (
StateFilter . freeze (
{
EventTypes . Member : { " @wombat:test " , " @alicia:test " } ,
" some.other.state.type " : None ,
} ,
include_others = False ,
) . return_expanded ( ) ,
StateFilter . freeze (
{ EventTypes . Member : { " @wombat:test " , " @alicia:test " } } ,
include_others = True ,
) ,
)
# If there is a wildcard in the non-member portion of the filter,
# it's expanded to include ALL non-member events.
# (Case: non-member-only filter)
self . assertEqual (
StateFilter . freeze (
{
" some.other.state.type " : None ,
} ,
include_others = False ,
) . return_expanded ( ) ,
StateFilter . freeze ( { EventTypes . Member : set ( ) } , include_others = True ) ,
)
self . assertEqual (
StateFilter . freeze (
{
" some.other.state.type " : None ,
" yet.another.state.type " : { " wombat " } ,
} ,
include_others = False ,
) . return_expanded ( ) ,
StateFilter . freeze ( { EventTypes . Member : set ( ) } , include_others = True ) ,
)