async def test_smoke(self):
        ni = 0
        async with MockAdminAPI() as client:
            nodes_config_resp = await client.getNodesConfig(
                NodesFilter(node=NodeID(node_index=ni))
            )
            nodes_state_resp = await client.getNodesState(
                NodesStateRequest(filter=NodesFilter(node=NodeID(node_index=ni)))
            )
            maintenances_resp = await client.getMaintenances(MaintenancesFilter())

        nc = nodes_config_resp.nodes[0]
        ns = nodes_state_resp.states[0]
        mnt_ids = set()
        for mnt in maintenances_resp.maintenances:
            for s in mnt.shards:
                if s.node.node_index == ni:
                    mnt_ids.add(mnt.group_id)
            for n in mnt.sequencer_nodes:
                if n.node_index == ni:
                    mnt_ids.add(mnt.group_id)
        mnts = tuple(
            sorted(
                (
                    mnt
                    for mnt in maintenances_resp.maintenances
                    if mnt.group_id in mnt_ids
                ),
                key=operator.attrgetter("group_id"),
            )
        )

        nv = NodeView(node_config=nc, node_state=ns, maintenances=mnts)

        self._validate(nv, nc, ns, mnts)
Example #2
0
 def node_index_to_node_view(self) -> Dict[int, NodeView]:
     if self._node_index_to_node_view is None:
         self._node_index_to_node_view = {
             ni: NodeView(
                 node_state=self.node_index_to_node_state[ni],
                 node_config=self.node_index_to_node_config[ni],
                 maintenances=self.node_index_to_maintenances[ni],
             )
             for ni in self.node_indexes
         }
     return self._node_index_to_node_view
 def test_empty(self):
     nc = NodeConfig(
         node_index=0,
         data_address=gen_SocketAddress(),
         roles=set(),
         location_per_scope={},
         name="",
     )
     ns = NodeState(node_index=0)
     mnts = []
     self._validate(NodeView(nc, ns, mnts), nc, ns, mnts)
Example #4
0
 def test_unix_socket(self):
     nc = NodeConfig(
         node_index=0,
         data_address=SocketAddress(address_family=SocketAddressFamily.UNIX,
                                    path="/path/to/unix.sock").to_thrift(),
         roles=set(),
         location_per_scope={},
         name="",
     )
     ns = NodeState(node_index=0)
     mnts = []
     self._validate(NodeView(nc, ns, mnts), nc, ns, mnts)
Example #5
0
 def _node_index_to_node_view(self) -> Dict[int, NodeView]:
     if self._node_index_to_node_view_dict is None:
         self._node_index_to_node_view_dict = {
             ni: NodeView(
                 node_config=self._node_index_to_node_config[ni],
                 node_state=self._node_index_to_node_state[ni],
                 maintenances=self._node_index_to_maintenances[ni],
             )
             for ni in self._node_indexes
         }
     # pyre-fixme[7]: Expected `Dict[int, NodeView]` but got `Optional[Dict[int,
     #  NodeView]]`.
     return self._node_index_to_node_view_dict
Example #6
0
    async def test_smoke(self):
        ni = 0
        async with MockAdminAPI() as client:
            cv = await get_cluster_view(client)
            maintenances_resp = await apply_maintenance(
                client=client,
                shards=[
                    ShardID(
                        node=cv.get_node_view_by_node_index(0).node_id, shard_index=1
                    )
                ],
                sequencer_nodes=[cv.get_node_view_by_node_index(0).node_id],
            )
            (
                nodes_config_resp,
                nodes_state_resp,
                maintenances_resp,
            ) = await asyncio.gather(
                client.getNodesConfig(NodesFilter(node=NodeID(node_index=ni))),
                client.getNodesState(
                    NodesStateRequest(filter=NodesFilter(node=NodeID(node_index=ni)))
                ),
                client.getMaintenances(MaintenancesFilter()),
            )

        nc = [n for n in nodes_config_resp.nodes if n.node_index == ni][0]
        ns = [n for n in nodes_state_resp.states if n.node_index == ni][0]
        mnt_ids = set()
        for mnt in maintenances_resp.maintenances:
            for s in mnt.shards:
                if s.node.node_index == ni:
                    mnt_ids.add(mnt.group_id)
            for n in mnt.sequencer_nodes:
                if n.node_index == ni:
                    mnt_ids.add(mnt.group_id)
        mnts = tuple(
            sorted(
                (
                    mnt
                    for mnt in maintenances_resp.maintenances
                    if mnt.group_id in mnt_ids
                ),
                key=operator.attrgetter("group_id"),
            )
        )

        nv = NodeView(node_config=nc, node_state=ns, maintenances=mnts)

        self._validate(nv, nc, ns, mnts)
 def test_no_name(self):
     addr = gen_SocketAddress()
     self.assertEqual(
         NodeView(
             node_config=NodeConfig(
                 node_index=0,
                 data_address=addr,
                 roles=set(),
                 location_per_scope={},
                 name="",
             ),
             node_state=NodeState(node_index=0),
             maintenances=[],
         ).node_name,
         str(SocketAddress.from_thrift(addr)),
     )
 async def test_mismatch(self):
     async with MockAdminAPI() as client:
         (
             nodes_config_resp,
             nodes_state_resp,
             maintenances_resp,
         ) = await asyncio.gather(
             client.getNodesConfig(NodesFilter(node=NodeID(node_index=0))),
             client.getNodesState(
                 NodesStateRequest(filter=NodesFilter(node=NodeID(node_index=1)))
             ),
             client.getMaintenances(MaintenancesFilter()),
         )
     with self.assertRaises(ValueError):
         NodeView(
             node_config=nodes_config_resp.nodes[0],
             node_state=nodes_state_resp.states[0],
             maintenances=maintenances_resp.maintenances,
         )
    def _validate(
        self,
        nv: NodeView,
        nc: NodeConfig,
        ns: NodeState,
        mnts: Tuple[MaintenanceDefinition, ...],
    ):
        self.assertEqual(nv.node_config, nc)

        self.assertEqual(nv.node_state, ns)

        self.assertEqual(nv.maintenances, mnts)

        self.assertEqual(nv.node_index, nc.node_index)

        if nc.name:
            self.assertEqual(nv.node_name, nc.name)
        else:
            self.assertEqual(
                nv.node_name, str(SocketAddress.from_thrift(nc.data_address))
            )

        self.assertEqual(nv.data_address, SocketAddress.from_thrift(nc.data_address))

        if nv.thrift_address.address_family == SocketAddressFamily.INET:
            assert nv.thrift_address.address is not None

            from_nc = SocketAddress.from_thrift(nc.data_address)
            assert from_nc.address is not None

            self.assertEqual(nv.thrift_address.port, 6440)
            self.assertEqual(
                nv.thrift_address.address.compressed, from_nc.address.compressed
            )

        self.assertEqual(
            nv.node_id,
            NodeID(node_index=nc.node_index, address=nc.data_address, name=nc.name),
        )

        self.assertEqual(nv.location, nc.location)

        self.assertEqual(nv.location_per_scope, nc.location_per_scope)

        self.assertEqual(nv.roles, nc.roles)

        for r in Role:
            self.assertEqual(nv.has_role(r), r in nc.roles)

        self.assertEqual(nv.is_sequencer, Role.SEQUENCER in nc.roles)
        self.assertEqual(nv.is_storage, Role.STORAGE in nc.roles)
        self.assertEqual(nv.daemon_state, ns.daemon_state)

        if Role.SEQUENCER in nc.roles:
            assert nc.sequencer is not None
            self.assertEqual(nv.sequencer_config, nc.sequencer)
            self.assertEqual(nv.sequencer_weight, nc.sequencer.weight)

            assert ns.sequencer_state is not None
            self.assertEqual(nv.sequencer_state, ns.sequencer_state)
            self.assertEqual(nv.sequencing_state, ns.sequencer_state.state)
        else:
            self.assertIsNone(nv.sequencer_config)
            self.assertIsNone(nv.sequencer_state)
            self.assertIsNone(nv.sequencer_weight)
            self.assertIsNone(nv.sequencing_state)

        if Role.STORAGE in nc.roles:
            assert nc.storage is not None
            assert ns.shard_states is not None
            self.assertEqual(nv.storage_config, nc.storage)
            self.assertEqual(nv.storage_weight, nc.storage.weight)
            self.assertEqual(nv.num_shards, nc.storage.num_shards)
            self.assertEqual(nv.shard_states, ns.shard_states)

            self.assertListEqual(
                nv.shards_data_health, [s.data_health for s in ns.shard_states]
            )
            self.assertEqual(
                nv.shards_data_health_count,
                Counter(s.data_health for s in ns.shard_states),
            )

            self.assertListEqual(
                nv.shards_current_storage_state,
                [s.current_storage_state for s in ns.shard_states],
            )

            self.assertEqual(
                nv.shards_current_storage_state_count,
                Counter(s.current_storage_state for s in ns.shard_states),
            )

            self.assertListEqual(
                nv.shards_current_operational_state,
                [s.current_operational_state for s in ns.shard_states],
            )

            self.assertEqual(
                nv.shards_current_operational_state_count,
                Counter(s.current_operational_state for s in ns.shard_states),
            )

            self.assertListEqual(
                nv.shards_membership_storage_state,
                [s.storage_state for s in ns.shard_states],
            )

            self.assertEqual(
                nv.shards_membership_storage_state_count,
                Counter(s.storage_state for s in ns.shard_states),
            )

            self.assertListEqual(
                nv.shards_metadata_state, [s.metadata_state for s in ns.shard_states]
            )

            self.assertEqual(
                nv.shards_metadata_state_count,
                Counter(s.metadata_state for s in ns.shard_states),
            )
        else:
            self.assertIsNone(nv.storage_config)
            self.assertIsNone(nv.storage_weight)
            self.assertIsNone(nv.num_shards)
            self.assertEqual(nv.shard_states, [])
Example #10
0
    def _validate(
        self,
        cv: ClusterView,
        ncs: List[NodeConfig],
        nss: List[NodeState],
        mnts: Tuple[MaintenanceDefinition, ...],
    ):
        nis = sorted(nc.node_index for nc in ncs)
        ni_to_nc = {nc.node_index: nc for nc in ncs}
        ni_to_ns = {ns.node_index: ns for ns in nss}
        ni_to_mnts: Dict[int,
                         List[MaintenanceDefinition]] = {ni: []
                                                         for ni in nis}
        for mnt in mnts:
            mnt_nis = set()
            for s in mnt.shards:
                assert s.node.node_index is not None
                mnt_nis.add(s.node.node_index)
            for n in mnt.sequencer_nodes:
                assert n.node_index is not None
                mnt_nis.add(n.node_index)
            for ni in mnt_nis:
                ni_to_mnts[ni].append(mnt)

        self.assertEqual(sorted(cv.get_all_node_indexes()),
                         sorted(ni_to_nc.keys()))

        self.assertEqual(
            sorted(cv.get_all_node_views(),
                   key=operator.attrgetter("node_index")),
            sorted(
                (NodeView(
                    node_config=ni_to_nc[ni],
                    node_state=ni_to_ns[ni],
                    maintenances=tuple(ni_to_mnts[ni]),
                ) for ni in ni_to_nc.keys()),
                key=operator.attrgetter("node_index"),
            ),
        )

        self.assertEqual(sorted(cv.get_all_node_names()),
                         sorted(nc.name for nc in ncs))

        self.assertEqual(sorted(cv.get_all_maintenance_ids()),
                         sorted(mnt.group_id for mnt in mnts))

        self.assertEqual(
            sorted(cv.get_all_maintenances(),
                   key=operator.attrgetter("group_id")),
            sorted(mnts, key=operator.attrgetter("group_id")),
        )

        for ni in nis:
            nn = ni_to_nc[ni].name
            nc = ni_to_nc[ni]
            ns = ni_to_ns[ni]
            mnts = tuple(ni_to_mnts[ni])
            nv = NodeView(node_config=ni_to_nc[ni],
                          node_state=ni_to_ns[ni],
                          maintenances=mnts)

            self.assertEqual(cv.get_node_view_by_node_index(ni), nv)
            self.assertEqual(cv.get_node_name_by_node_index(ni), nn)
            self.assertEqual(cv.get_node_config_by_node_index(ni), nc)
            self.assertEqual(cv.get_node_state_by_node_index(ni), ns)
            self.assertEqual(cv.get_maintenances_by_node_index(ni), mnts)

            self.assertEqual(cv.get_node_view_by_node_name(nn), nv)
            self.assertEqual(cv.get_node_index_by_node_name(nn), ni)
            self.assertEqual(cv.get_node_config_by_node_name(nn), nc)
            self.assertEqual(cv.get_node_state_by_node_name(nn), ns)
            self.assertEqual(cv.get_maintenances_by_node_name(nn), mnts)

            self.assertEqual(cv.get_node_view(node_name=nn), nv)
            self.assertEqual(cv.get_node_index(node_name=nn), ni)
            self.assertEqual(cv.get_node_config(node_name=nn), nc)
            self.assertEqual(cv.get_node_state(node_name=nn), ns)
            self.assertEqual(cv.get_maintenances(node_name=nn), mnts)

            self.assertEqual(cv.get_node_view(node_index=ni), nv)
            self.assertEqual(cv.get_node_name(node_index=ni), nn)
            self.assertEqual(cv.get_node_config(node_index=ni), nc)
            self.assertEqual(cv.get_node_state(node_index=ni), ns)
            self.assertEqual(cv.get_maintenances(node_index=ni), mnts)

        with self.assertRaises(ValueError):
            cv.get_node_view(None, None)

        with self.assertRaises(ValueError):
            cv.get_node_config(None, None)

        with self.assertRaises(ValueError):
            cv.get_node_state(None, None)

        with self.assertRaises(ValueError):
            cv.get_maintenances(None, None)

        # mismatch node_index and node_name
        if len(nis) > 1:
            nn = ni_to_nc[nis[0]].name
            ni = nis[1]
            with self.assertRaises(ValueError):
                cv.get_node_view(ni, nn)

            with self.assertRaises(ValueError):
                cv.get_node_config(ni, nn)

            with self.assertRaises(ValueError):
                cv.get_node_state(ni, nn)

            with self.assertRaises(ValueError):
                cv.get_maintenances(ni, nn)

        # non-existent node_index
        with self.assertRaises(KeyError):
            cv.get_node_view(node_index=max(nis) + 1)

        # non-existent node_name
        with self.assertRaises(KeyError):
            nns = {nc.name for nc in ncs}
            while True:
                nn = gen_word()
                if nn not in nns:
                    break
            cv.get_node_view(node_name=nn)

        for mnt in mnts:
            assert mnt.group_id is not None
            self.assertEqual(cv.get_maintenance_by_id(mnt.group_id), mnt)
Example #11
0
    def _validate(
        self,
        cv: ClusterView,
        ncs: List[NodeConfig],
        nss: List[NodeState],
        mnts: Tuple[MaintenanceDefinition, ...],
    ) -> None:
        nis = sorted(nc.node_index for nc in ncs)
        ni_to_nc = {nc.node_index: nc for nc in ncs}
        ni_to_ns = {ns.node_index: ns for ns in nss}
        ni_to_mnts: Dict[int,
                         List[MaintenanceDefinition]] = {ni: []
                                                         for ni in nis}
        for mnt in mnts:
            mnt_nis = set()
            for s in mnt.shards:
                assert s.node.node_index is not None
                mnt_nis.add(s.node.node_index)
            for n in mnt.sequencer_nodes:
                assert n.node_index is not None
                mnt_nis.add(n.node_index)
            for ni in mnt_nis:
                ni_to_mnts[ni].append(mnt)

        self.assertEqual(sorted(cv.get_all_node_indexes()),
                         sorted(ni_to_nc.keys()))

        self.assertEqual(
            sorted(cv.get_all_node_views(),
                   key=operator.attrgetter("node_index")),
            sorted(
                (NodeView(
                    node_config=ni_to_nc[ni],
                    node_state=ni_to_ns[ni],
                    maintenances=tuple(ni_to_mnts[ni]),
                ) for ni in ni_to_nc.keys()),
                key=operator.attrgetter("node_index"),
            ),
        )

        self.assertEqual(sorted(cv.get_all_node_names()),
                         sorted(nc.name for nc in ncs))

        self.assertEqual(
            sorted(cv.get_all_maintenance_ids()),
            # pyre-fixme[6]: Expected `Iterable[Variable[_LT (bound to
            #  _SupportsLessThan)]]` for 1st param but got
            #  `Generator[typing.Optional[str], None, None]`.
            sorted(mnt.group_id for mnt in mnts),
        )

        self.assertEqual(
            sorted(cv.get_all_maintenances(),
                   key=operator.attrgetter("group_id")),
            sorted(mnts, key=operator.attrgetter("group_id")),
        )

        for ni in nis:
            nn = ni_to_nc[ni].name
            nc = ni_to_nc[ni]
            ns = ni_to_ns[ni]
            node_mnts = tuple(ni_to_mnts[ni])
            nv = NodeView(
                node_config=ni_to_nc[ni],
                node_state=ni_to_ns[ni],
                maintenances=node_mnts,
            )

            self.assertEqual(cv.get_node_view_by_node_index(ni), nv)
            self.assertEqual(cv.get_node_name_by_node_index(ni), nn)
            self.assertEqual(cv.get_node_config_by_node_index(ni), nc)
            self.assertEqual(cv.get_node_state_by_node_index(ni), ns)
            self.assertEqual(cv.get_node_maintenances_by_node_index(ni),
                             node_mnts)

            self.assertEqual(cv.get_node_view_by_node_name(nn), nv)
            self.assertEqual(cv.get_node_index_by_node_name(nn), ni)
            self.assertEqual(cv.get_node_config_by_node_name(nn), nc)
            self.assertEqual(cv.get_node_state_by_node_name(nn), ns)
            self.assertEqual(cv.get_node_maintenances_by_node_name(nn),
                             node_mnts)

            self.assertEqual(cv.get_node_view(node_name=nn), nv)
            self.assertEqual(cv.get_node_index(node_name=nn), ni)
            self.assertEqual(cv.get_node_config(node_name=nn), nc)
            self.assertEqual(cv.get_node_state(node_name=nn), ns)
            self.assertEqual(cv.get_node_maintenances(node_name=nn), node_mnts)

            self.assertEqual(cv.get_node_view(node_index=ni), nv)
            self.assertEqual(cv.get_node_name(node_index=ni), nn)
            self.assertEqual(cv.get_node_config(node_index=ni), nc)
            self.assertEqual(cv.get_node_state(node_index=ni), ns)
            self.assertEqual(cv.get_node_maintenances(node_index=ni),
                             node_mnts)

        with self.assertRaises(ValueError):
            cv.get_node_view(None, None)

        with self.assertRaises(ValueError):
            cv.get_node_config(None, None)

        with self.assertRaises(ValueError):
            cv.get_node_state(None, None)

        with self.assertRaises(ValueError):
            cv.get_node_maintenances(None, None)

        # mismatch node_index and node_name
        if len(nis) > 1:
            nn = ni_to_nc[nis[0]].name
            ni = nis[1]
            with self.assertRaises(ValueError):
                cv.get_node_view(ni, nn)

            with self.assertRaises(ValueError):
                cv.get_node_config(ni, nn)

            with self.assertRaises(ValueError):
                cv.get_node_state(ni, nn)

            with self.assertRaises(ValueError):
                cv.get_node_maintenances(ni, nn)

        # non-existent node_index
        with self.assertRaises(NodeNotFoundError):
            cv.get_node_view(node_index=max(nis) + 1)

        # non-existent node_name
        with self.assertRaises(NodeNotFoundError):
            nns = {nc.name for nc in ncs}
            nn: str = ""
            while True:
                nn = gen_word()
                if nn not in nns:
                    break
            cv.get_node_view(node_name=nn)

        for mnt in mnts:
            group_id: str = mnt.group_id or ""
            self.assertEqual(cv.get_maintenance_by_id(group_id), mnt)
            self.assertTupleEqual(
                cv.get_node_indexes_by_maintenance_id(group_id),
                tuple(
                    sorted(
                        set({
                            n.node_index
                            for n in mnt.sequencer_nodes
                            if n.node_index is not None
                        }).union({
                            s.node.node_index
                            for s in mnt.shards
                            if s.node.node_index is not None
                        }))),
            )
            self.assertEqual(group_id,
                             cv.get_maintenance_view_by_id(group_id).group_id)

        self.assertListEqual(
            # pyre-fixme[6]: Expected `Iterable[Variable[_LT (bound to
            #  _SupportsLessThan)]]` for 1st param but got
            #  `Generator[typing.Optional[str], None, None]`.
            sorted(m.group_id for m in mnts),
            sorted(mv.group_id for mv in cv.get_all_maintenance_views()),
        )

        # expand_shards
        self.assertEqual(
            cv.expand_shards(shards=[
                ShardID(node=NodeID(node_index=nis[0]), shard_index=0)
            ]),
            (ShardID(
                node=NodeID(
                    node_index=ni_to_nc[nis[0]].node_index,
                    name=ni_to_nc[nis[0]].name,
                    address=ni_to_nc[nis[0]].data_address,
                ),
                shard_index=0,
            ), ),
        )
        num_shards: int = getattr(ni_to_nc[nis[0]], "storage",
                                  StorageConfig()).num_shards
        self.assertEqual(
            len(
                cv.expand_shards(shards=[
                    ShardID(node=NodeID(node_index=nis[0]),
                            shard_index=ALL_SHARDS)
                ])),
            num_shards,
        )
        self.assertEqual(
            len(
                cv.expand_shards(shards=[
                    ShardID(node=NodeID(node_index=nis[0]),
                            shard_index=ALL_SHARDS),
                    ShardID(node=NodeID(node_index=nis[0]),
                            shard_index=ALL_SHARDS),
                    ShardID(node=NodeID(node_index=nis[1]),
                            shard_index=ALL_SHARDS),
                ])),
            getattr(ni_to_nc[nis[0]], "storage", StorageConfig()).num_shards +
            getattr(ni_to_nc[nis[1]], "storage", StorageConfig()).num_shards,
        )
        self.assertEqual(
            len(
                cv.expand_shards(
                    shards=[
                        ShardID(node=NodeID(node_index=nis[0]),
                                shard_index=ALL_SHARDS),
                        ShardID(node=NodeID(node_index=nis[1]), shard_index=0),
                    ],
                    node_ids=[NodeID(node_index=0)],
                )),
            getattr(ni_to_nc[nis[0]], "storage", StorageConfig()).num_shards +
            1,
        )

        # normalize_node_id
        self.assertEqual(
            cv.normalize_node_id(NodeID(node_index=nis[0])),
            NodeID(
                node_index=nis[0],
                address=ni_to_nc[nis[0]].data_address,
                name=ni_to_nc[nis[0]].name,
            ),
        )
        self.assertEqual(
            cv.normalize_node_id(NodeID(name=ni_to_nc[nis[0]].name)),
            NodeID(
                node_index=nis[0],
                address=ni_to_nc[nis[0]].data_address,
                name=ni_to_nc[nis[0]].name,
            ),
        )

        # get_node_id
        self.assertEqual(cv.get_node_id(node_index=0).node_index, 0)

        # search_maintenances
        storages_node_views = [
            nv for nv in cv.get_all_node_views() if nv.is_storage
        ]
        sequencers_node_views = [
            nv for nv in cv.get_all_node_views() if nv.is_sequencer
        ]
        self.assertEqual(len(cv.search_maintenances()), len(mnts))
        self.assertEqual(len(cv.search_maintenances(node_ids=[])), 0)
        self.assertEqual(
            len(
                cv.search_maintenances(sequencer_nodes=[
                    storages_node_views[3].node_id,
                    sequencers_node_views[4].node_id,
                ])),
            1,
        )
        self.assertEqual(
            len(
                cv.search_maintenances(node_ids=[
                    storages_node_views[3].node_id,
                    sequencers_node_views[4].node_id,
                ])),
            1,
        )
        self.assertEqual(
            len(
                cv.search_maintenances(shards=[
                    ShardID(node=storages_node_views[1].node_id, shard_index=1)
                ])),
            1,
        )

        # shard_target_state
        self.assertEqual(
            len(
                cv.search_maintenances(
                    shard_target_state=ShardOperationalState.MAY_DISAPPEAR)),
            3,
        )
        self.assertEqual(
            len(
                cv.search_maintenances(
                    shard_target_state=ShardOperationalState.DRAINED)),
            0,
        )

        # sequencer_target_state
        self.assertEqual(
            len(
                cv.search_maintenances(
                    sequencer_target_state=SequencingState.ENABLED)),
            0,
        )
        self.assertEqual(
            len(
                cv.search_maintenances(
                    sequencer_target_state=SequencingState.DISABLED)),
            3,
        )

        self.assertEqual(len(cv.search_maintenances(user="******")), 1)
        self.assertEqual(len(cv.search_maintenances(reason="whatever")), 1)

        self.assertEqual(len(cv.search_maintenances(skip_safety_checks=True)),
                         0)
        self.assertEqual(len(cv.search_maintenances(skip_safety_checks=False)),
                         4)

        self.assertEqual(
            len(cv.search_maintenances(force_restore_rebuilding=True)), 0)
        self.assertEqual(
            len(cv.search_maintenances(force_restore_rebuilding=False)), 4)

        self.assertEqual(
            len(cv.search_maintenances(allow_passive_drains=True)), 0)
        self.assertEqual(
            len(cv.search_maintenances(allow_passive_drains=False)), 4)

        self.assertEqual(
            len(cv.search_maintenances(group_id=mnts[0].group_id)), 1)

        self.assertEqual(
            len(
                cv.search_maintenances(
                    progress=MaintenanceProgress.IN_PROGRESS)), 4)