test_initialization.py 9.46 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# -*- coding: utf-8 -*-
#
# This file is part of the bliss project
#
# Copyright (c) 2015-2020 Beamline Control Unit, ESRF
# Distributed under the GNU LGPLv3. See LICENSE for more info.
import sys
import os
import pytest
from unittest import mock

from bliss.config import channels
from bliss.config.static import get_config
from bliss.controllers.motor import Controller as MotController


class DummyCtrl(MotController):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.init_order = list()
        self.init_axis_order = list()

    def initialize(self):
        self.init_order.append("S")

    def initialize_hardware(self):
        self.init_order.append("H")

    def initialize_axis(self, axis):
        self.init_axis_order.append("S")

    def initialize_hardware_axis(self, axis):
        self.init_axis_order.append("H")

    def set_velocity(self, *args):
        pass

    def read_velocity(self, *args):
        return 0.0

    def set_acceleration(self, *args):
        pass

    def read_acceleration(self, *args):
        return 0.0


@pytest.fixture
def dummy_axis_1(beacon):
    sys.path.append(os.path.dirname(__file__))
    yield beacon.get("dummy_axis_1")
    sys.path.pop()


def test_initialization_controller_order(dummy_axis_1):
    dummy_axis_1.position  # init everything
    assert dummy_axis_1.controller.init_order == ["S", "H"]


def test_initialization_axis_order(dummy_axis_1):
    dummy_axis_1.position  # init everything
    assert dummy_axis_1.controller.init_axis_order == ["S", "H"]


def test_motor_shared(beacon):
    """
    Simulating motor shared between two sessions
    The second instance should be able to get the configuration
    while the first session is moving the motor
    """
    config = get_config()
    roby1 = config.get("roby")
    config._clear_instances()
    roby1.move(0, wait=False)
    channels.clear_cache(roby1, roby1.controller)
    roby1.controller._Controller__initialized_axis[roby1] = False
    roby2 = config.get("roby")
    roby2.__info__()
    roby1.stop()


def test_axis_disable_broken_init(default_session):
    def faulty_initialize(*args, **kwargs):
        raise RuntimeError("FAILED TO INITIALIZE")

    with mock.patch(
        "bliss.controllers.motors.mockup.Mockup.initialize_axis",
        wraps=faulty_initialize,
    ):
        roby = default_session.config.get("roby")
        with pytest.raises(RuntimeError):
            roby.state
        assert roby.disabled

        # try to enable while motor cannot be initialized still
        with pytest.raises(RuntimeError):
            roby.enable()
        assert roby.disabled

    assert roby.disabled
    # motor stays disabled until .enable() is called
    # all calls doing a lazy init will fail immediately
    # without accessing hw
    roby.enable()
    assert "READY" in roby.state
    assert not roby.disabled


def test_broken_controller_init(default_session):
    def faulty_initialize(*args, **kwargs):
        raise RuntimeError("FAILED TO INITIALIZE")

Perceval Guillou's avatar
Perceval Guillou committed
113
114
115
116
117
118
119
120
121
    config = get_config()

    # === config._name2instance and config._name2cache are empty
    # print("=== name2instance:", list(config._name2instance.keys()))
    # print("=== name2cache:", list(config._name2cache.keys()))

    assert list(config._name2instance.keys()) == []
    assert list(config._name2cache.keys()) == []

122
123
124
    with mock.patch(
        "bliss.controllers.motors.mockup.Mockup.initialize", wraps=faulty_initialize
    ):
Perceval Guillou's avatar
Perceval Guillou committed
125
126
        # === expecting failure during plugin.from_config => BlissController._controller_init()
        with pytest.raises(RuntimeError, match="FAILED TO INITIALIZE"):
127
128
            default_session.config.get("roby")

129
130
        # === now config._name2instance is still empty because _controller_init() has failed and roby was not instanciated
        # === config._name2cache is also empty because cacheditems have been removed when _controller_init() has failed
131
132
133
        # print("=== match=FAILED TO INITIALIZE")
        # print("=== name2instance:", list(config._name2instance.keys()))
        # print("=== name2cache:", list(config._name2cache.keys()))
Perceval Guillou's avatar
Perceval Guillou committed
134
        assert list(config._name2instance.keys()) == []
135
136
137
        assert list(config._name2cache.keys()) == []

        # === expecting same failure during plugin.from_config => BlissController._controller_init()
Perceval Guillou's avatar
Perceval Guillou committed
138
        with pytest.raises(
139
            RuntimeError, match="FAILED TO INITIALIZE"
Perceval Guillou's avatar
Perceval Guillou committed
140
        ):  # Controller is disabled
141
142
            default_session.config.get("roby")

143
144
        # === now config._name2instance is still empty because _controller_init() has failed and roby was not instanciated
        # === config._name2cache is also empty because cacheditems have been removed when _controller_init() has failed
145
146
147
        # print("=== match=FAILED TO INITIALIZE")
        # print("=== name2instance:", list(config._name2instance.keys()))
        # print("=== name2cache:", list(config._name2cache.keys()))
Perceval Guillou's avatar
Perceval Guillou committed
148
        assert list(config._name2instance.keys()) == []
149
        assert list(config._name2cache.keys()) == []
Perceval Guillou's avatar
Perceval Guillou committed
150

151
152
153
154
    with mock.patch(
        "bliss.controllers.motors.mockup.Mockup.initialize_hardware",
        wraps=faulty_initialize,
    ):
Perceval Guillou's avatar
Perceval Guillou committed
155

156
157
        # === now controller will be successfully initialized
        # === and roby will be initialized too (because with the lazy init faulty hardware is not seen yet)
158
159
        roby = default_session.config.get("roby")
        assert roby
Perceval Guillou's avatar
Perceval Guillou committed
160
161
162
163
        assert roby._disabled == False  # not yet disabled because of lasy hardware init
        assert (
            roby.controller._disabled == False
        )  # not yet disabled because of lasy hardware init
164
165
166
167
        # print("=== assert roby True")
        # print("=== name2instance:", list(config._name2instance.keys()))
        # print("=== name2cache:", list(config._name2cache.keys()))
        # assert "roby" in list(config._name2instance.keys())
168
169
170
171
        assert "roby" not in list(
            config._name2cache.keys()
        )  # roby has been has been initialized and the removed from config cached items
        assert "robu" in list(config._name2cache.keys())  # other items have been cached
Perceval Guillou's avatar
Perceval Guillou committed
172
173
174

        # === accessing position will force controller to init its hardware and will fail
        with pytest.raises(RuntimeError, match="FAILED TO INITIALIZE"):
175
            roby.position  # will call initialize_hardware => will fail
Perceval Guillou's avatar
Perceval Guillou committed
176
177
178
        # axis roby and controller are now disabled
        assert roby._disabled == True
        assert roby.controller._disabled == True
179
180

    # roby and robu are on the same controller ;
Perceval Guillou's avatar
Perceval Guillou committed
181
    # controller is disabled because hardware init has failed
182
183
    with pytest.raises(RuntimeError, match="Controller is disabled"):
        default_session.config.get("robu")
Perceval Guillou's avatar
Perceval Guillou committed
184
    assert "robu" not in list(
185
186
187
        config._name2instance.keys()
    )  # because robu instantiation has failed
    assert "robu" in list(
Perceval Guillou's avatar
Perceval Guillou committed
188
        config._name2cache.keys()
189
    )  # robu has been put back in cache because instantiation has failed
190
191
192
193

    with pytest.raises(RuntimeError, match="Axis roby is disabled"):
        # axis is already disabled
        roby.position
Perceval Guillou's avatar
Perceval Guillou committed
194
195
    assert roby._disabled == True
    assert roby.controller._disabled == True
196
197
198

    with pytest.raises(RuntimeError, match="Controller is disabled"):
        roby.enable()
Perceval Guillou's avatar
Perceval Guillou committed
199
200
201
    assert roby._disabled == True
    assert roby.controller._disabled == True

202
    # === call _init() to re-enable the controller
Perceval Guillou's avatar
Perceval Guillou committed
203
204
205
206
207
208
209
210
211
212
213
214
215
    roby.controller._init()
    assert roby.controller._disabled == False
    roby2 = default_session.config.get("roby")
    assert roby is roby2

    roby.enable()
    assert roby._disabled == False

    roby.position

    robu = default_session.config.get("robu")
    robu.position

216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244

def test_encoder_disable_broken_init(default_session):
    def faulty_initialize(*args, **kwargs):
        raise RuntimeError("FAILED TO INITIALIZE")

    with mock.patch(
        "bliss.controllers.motors.mockup.Mockup.initialize_encoder",
        wraps=faulty_initialize,
    ):
        m1 = default_session.config.get(
            "m1"
        )  # have to get axis first, because mockup does not know how to retrieve axis from encoder, if there is no axis there is no encoder pos. unless explicitely set
        enc = default_session.config.get("m1enc")
        with pytest.raises(RuntimeError):
            enc.raw_read
        assert enc.disabled

        # try to enable while motor cannot be initialized still
        with pytest.raises(RuntimeError):
            enc.enable()
        assert enc.disabled

    assert enc.disabled
    # encoder stays disabled until .enable() is called
    # all calls doing a lazy init will fail immediately
    # without accessing hw
    enc.enable()
    assert enc.raw_read == 0.0
    assert not enc.disabled
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264


def test_initialized_cache(beacon):
    roby = beacon.get("roby")
    llbend1 = beacon.get("llbend1")

    # /!\ check roby and llbend1 are on 2 different mockup controller instances
    assert type(roby.controller) == type(llbend1.controller)
    assert roby.controller != llbend1.controller

    roby_controller_init_cache = channels.Cache(roby.controller, "initialized")
    llbend1_controller_init_cache = channels.Cache(llbend1.controller, "initialized")
    assert roby_controller_init_cache != llbend1_controller_init_cache
    assert roby_controller_init_cache.name != llbend1_controller_init_cache.name

    # check that another motor on the same controller has the same 'initialized' cache
    m1 = beacon.get("m1")
    assert roby.controller == m1.controller
    m1_controller_init_cache = channels.Cache(m1.controller, "initialized")
    assert m1_controller_init_cache == roby_controller_init_cache