async def test_workflow_connect_fail(
    data_store_mgr: DataStoreMgr,
    port_range,
    monkeypatch,
    caplog,
):
    """Simulate a failure during workflow connection.

    The data store should "rollback" any incidental changes made during the
    failed connection attempt by disconnecting from the workflow afterwards.

    Not an ideal test as we don't actually get a communication failure,
    the data store manager just skips contacting the workflow because
    we aren't providing a client for it to connect to, however, probably the
    best we can achieve without actually running a workflow.
    """
    # patch the zmq logic so that the connection doesn't fail at the first
    # hurdle
    monkeypatch.setattr(
        'cylc.flow.network.ZMQSocketBase._socket_bind', lambda *a, **k: None,
    )

    # start a ZMQ REPLY socket in order to claim an unused port
    w_id = Tokens(user='******', workflow='workflow_id').id
    try:
        context = zmq.Context()
        server = ZMQSocketBase(
            zmq.REP,
            context=context,
            workflow=w_id,
            bind=True,
        )
        server._socket_bind(*port_range)

        # register the workflow with the data store
        await data_store_mgr.register_workflow(w_id=w_id, is_active=False)
        contact_data = {
            'name': 'workflow_id',
            'owner': 'cylc',
            CFF.HOST: 'localhost',
            CFF.PORT: server.port,
            CFF.PUBLISH_PORT: server.port,
            CFF.API: 1
        }

        # try to connect to the workflow
        caplog.set_level(logging.DEBUG, data_store_mgr.log.name)
        await data_store_mgr.connect_workflow(w_id, contact_data)

        # the connection should fail because our ZMQ socket is not a
        # WorkflowRuntimeServer with the correct endpoints and auth
        assert [record.message for record in caplog.records] == [
            "[data-store] connect_workflow('~user/workflow_id', <dict>)",
            'failed to connect to ~user/workflow_id',
            "[data-store] disconnect_workflow('~user/workflow_id')",
        ]
    finally:
        # tidy up
        server.stop()
        context.destroy()
Ejemplo n.º 2
0
def test_single_port(myflow, port_range):
    """Test server on a single port and port in use exception."""
    context = zmq.Context()
    setup_keys(myflow)  # auth keys are required for comms
    serv1 = ZMQSocketBase(zmq.REP, context=context, suite=myflow, bind=True)
    serv2 = ZMQSocketBase(zmq.REP, context=context, suite=myflow, bind=True)

    serv1._socket_bind(*port_range)
    port = serv1.port

    with pytest.raises(CylcError, match=r"Address already in use"):
        serv2._socket_bind(port, port)

    serv2.stop()
    serv1.stop()
    context.destroy()
Ejemplo n.º 3
0
def test_single_port():
    """Test server on a single port and port in use exception."""
    context = zmq.Context()
    create_auth_files('test_zmq')  # auth keys are required for comms
    serv1 = ZMQSocketBase(
        zmq.REP, context=context, suite='test_zmq', bind=True)
    serv2 = ZMQSocketBase(
        zmq.REP, context=context, suite='test_zmq', bind=True)

    serv1._socket_bind(*PORT_RANGE)
    port = serv1.port

    with pytest.raises(CylcError, match=r"Address already in use") as exc:
        serv2._socket_bind(port, port)

    serv2.stop()
    serv1.stop()
    context.destroy()