示例#1
0
def test_parse_misc_actions():
    proclang = '''
    main:
        1. CONTROL: Set injector_valve to open
        2. CONTROL: [p1 < 10] Disarm the remote control system
        3. PRIMARY: Approach the launch tower, disconnect the cylinder, and replace the cap
        4. OPS: [60s] Proceed with teardown
    '''
    suite = top.proclang.parse(proclang)

    expected_suite = top.ProcedureSuite([
        top.Procedure('main', [
            top.ProcedureStep(
                '1', top.StateChangeAction('injector_valve', 'open'), [
                    (top.Less('p1', 10), top.Transition('main', '2'))
                ], 'CONTROL'),
            top.ProcedureStep(
                '2', top.MiscAction('Disarm the remote control system'),
                [(top.Immediate(), top.Transition('main', '3'))], 'CONTROL'),
            top.ProcedureStep(
                '3',
                top.MiscAction(
                    'Approach the launch tower, disconnect the cylinder, and replace the cap'
                ), [(top.WaitFor(60e6), top.Transition('main', '4'))],
                'PRIMARY'),
            top.ProcedureStep('4', top.MiscAction('Proceed with teardown'), [],
                              'OPS')
        ])
    ])

    assert suite == expected_suite
示例#2
0
def test_procedure_duplicate_id_errors():
    s1 = top.ProcedureStep('s1', None, [], 'PRIMARY')
    s2 = top.ProcedureStep('s2', None, [], 'PRIMARY')
    s3 = top.ProcedureStep('s1', None, [], 'PRIMARY')

    with pytest.raises(ValueError):
        top.Procedure('p1', [s1, s2, s3])
示例#3
0
def test_time_advance():
    plumb_b = PlumbingBridge()
    control_b = ControlsBridge(plumb_b)
    proc_b = ProceduresBridge(plumb_b, control_b)

    procedure = top.Procedure('main', [
        top.ProcedureStep('1', top.StateChangeAction('injector_valve', 'open'),
                          [(top.Less('A', 75), top.Transition('main', '2'))],
                          'PRIMARY'),
        top.ProcedureStep('2', top.MiscAction('Approach the launch tower'), [],
                          'SECONDARY')
    ])
    proc_b.load_suite(top.ProcedureSuite([procedure]))

    plumb_eng = make_plumbing_engine()
    plumb_b.load_engine(plumb_eng)

    tol = 0.01

    proc_eng = proc_b._proc_eng

    proc_b.procStepForward()  # execute step 1
    assert not proc_eng.ready_to_proceed()
    assert plumb_eng.current_pressures('A') == 100
    assert plumb_eng.current_pressures('B') == 0

    plumb_b.timeAdvance()
    assert proc_eng.ready_to_proceed()
    # We expect pressures to equalize at 50 once the system is steady
    assert abs(plumb_eng.current_pressures('A') - 50) < tol
    assert abs(plumb_eng.current_pressures('B') - 50) < tol
示例#4
0
def test_parse_names_with_hyphens():
    proclang = '''
    main:
        1. PRIMARY: set A-200 to open
        2. PRIMARY: set vent-valve to closed
        3. BOB-THE-BUILDER: set K-5-B to open
        4. CONTROL: set C-AB-2 to closed
        5. OPS: set A-200 to semi-closed
    '''
    suite = top.proclang.parse(proclang)

    expected_suite = top.ProcedureSuite([
        top.Procedure('main', [
            top.ProcedureStep('1', top.StateChangeAction('A-200', 'open'), [
                (top.Immediate(), top.Transition('main', '2'))
            ], 'PRIMARY'),
            top.ProcedureStep(
                '2', top.StateChangeAction('vent-valve', 'closed'),
                [(top.Immediate(), top.Transition('main', '3'))], 'PRIMARY'),
            top.ProcedureStep('3', top.StateChangeAction('K-5-B', 'open'), [
                (top.Immediate(), top.Transition('main', '4'))
            ], 'BOB-THE-BUILDER'),
            top.ProcedureStep('4', top.StateChangeAction('C-AB-2', 'closed'), [
                (top.Immediate(), top.Transition('main', '5'))
            ], 'CONTROL'),
            top.ProcedureStep('5', top.StateChangeAction(
                'A-200', 'semi-closed'), [], 'OPS')
        ])
    ])

    assert suite == expected_suite
示例#5
0
def test_waitfor_latex_export():
    suite = top.ProcedureSuite([
        top.Procedure('main', [
            top.ProcedureStep(
                '1', top.StateChangeAction('injector_valve', 'open'),
                [(top.And([
                    top.WaitFor(10e6),
                    top.Or(
                        [top.Less('p1', 400.0),
                         top.GreaterEqual('p2', 17.0)])
                ]), top.Transition('main', '2'))], 'PRIMARY'),
            top.ProcedureStep('2', top.StateChangeAction(
                'vent_valve', 'closed'), [], 'PRIMARY')
        ])
    ])

    export = suite.export(top.ExportFormat.Latex)

    expected_export = textwrap.dedent(r'''        \subsection{main}
        \begin{checklist}
            \item \PRIMARY{} Open injector\_valve
            \item Wait 10 seconds and p1 is less than 400psi or p2 is greater than or equal to 17psi
            \item \PRIMARY{} Close vent\_valve
        \end{checklist}''')

    assert export == expected_export
示例#6
0
def test_procedure_suite_latex_export():
    s1 = top.ProcedureStep('s1',
                           top.StateChangeAction('remote fill valve', 'open'),
                           [], 'PRIMARY')
    s2 = top.ProcedureStep(
        's2', top.StateChangeAction('remote vent valve', 'closed'), [],
        'SECONDARY')

    proc_main = top.Procedure('main', [s1, s2])
    proc_abort = top.Procedure('abort', [s2])

    suite = top.ProcedureSuite([proc_main, proc_abort])

    export = suite.export(top.ExportFormat.Latex)

    expected_export = textwrap.dedent(r'''        \subsection{main}
        \begin{checklist}
            \item \PRIMARY{} Open remote fill valve
            \item \SECONDARY{} Close remote vent valve
        \end{checklist}

        \subsection{abort}
        \begin{checklist}
            \item \SECONDARY{} Close remote vent valve
        \end{checklist}''')

    assert export == expected_export
示例#7
0
def test_parse_combined_conditions():
    proclang = '''
    main:
        1. PRIMARY: set s to v
        2. PRIMARY: [p1 < 100 or 500s and p2 < 200] set s to v
    '''

    suite = top.proclang.parse(proclang)

    comp_or = top.Or([
        top.Less('p1', 100),
        top.And([top.WaitFor(1e6 * 500),
                 top.Less('p2', 200)])
    ])
    expected_suite = top.ProcedureSuite([
        top.Procedure('main', [
            top.ProcedureStep('1', top.StateChangeAction('s', 'v'), [
                (comp_or, top.Transition('main', '2'))
            ], 'PRIMARY'),
            top.ProcedureStep('2', top.StateChangeAction('s', 'v'), [],
                              'PRIMARY')
        ])
    ])

    assert suite == expected_suite
示例#8
0
def test_jump_to_step_normal():
    plumb_b = PlumbingBridge()
    control_b = ControlsBridge(plumb_b)
    proc_b = ProceduresBridge(plumb_b, control_b)

    procedure = top.Procedure('main', [
        top.ProcedureStep('1', top.StateChangeAction('injector_valve', 'open'),
                          [(top.Immediate(), top.Transition('main', '2'))],
                          'PRIMARY'),
        top.ProcedureStep(
            '2', top.StateChangeAction('injector_valve', 'closed'),
            [(top.Immediate(), top.Transition('main', '3'))], 'PRIMARY'),
        top.ProcedureStep(
            '3', top.StateChangeAction('injector_valve', 'closed'),
            [(top.Immediate(), top.Transition('main', '4'))], 'PRIMARY'),
        top.ProcedureStep('4', top.MiscAction('Approach the launch tower'), [],
                          'SECONDARY')
    ])

    proc_b.load_suite(top.ProcedureSuite([procedure]))

    plumb_eng = make_plumbing_engine()
    plumb_b.load_engine(plumb_eng)

    proc_eng = proc_b._proc_eng

    assert proc_eng.current_step == procedure.step_list[0]
    assert proc_eng.step_position == top.StepPosition.Before
    proc_b.procJump("2")
    assert proc_eng.current_step == procedure.step_list[1]
    assert proc_eng.step_position == top.StepPosition.After
    proc_b.procJump("4")
    assert proc_eng.current_step == procedure.step_list[3]
    assert proc_eng.step_position == top.StepPosition.After
示例#9
0
def test_parse_steps_with_multiple_comparisons():
    proclang = '''
    main:
        1. PRIMARY: set injector_valve to open
        2. PRIMARY: [p1 < 100 and p2 < 100 and p3 < 100] set vent_valve to closed
        3. PRIMARY: [p1 < 100 or  p2 < 100 or  p3 < 100] set vent_valve to open
        4. PRIMARY: [p1 < 100 and p2 < 100 and p3 < 100 or p1 < 100 and p2 < 100] set vent_valve to open
    '''
    suite = top.proclang.parse(proclang)

    p1 = top.Less('p1', 100)
    p2 = top.Less('p2', 100)
    p3 = top.Less('p3', 100)

    expected_suite = top.ProcedureSuite([
        top.Procedure('main', [
            top.ProcedureStep(
                '1', top.StateChangeAction('injector_valve', 'open'), [
                    (top.And([p1, p2, p3]), top.Transition('main', '2'))
                ], 'PRIMARY'),
            top.ProcedureStep('2', top.StateChangeAction(
                'vent_valve', 'closed'), [(top.Or(
                    [p1, p2, p3]), top.Transition('main', '3'))], 'PRIMARY'),
            top.ProcedureStep('3', top.StateChangeAction(
                'vent_valve', 'open'), [
                    (top.Or([top.And([p1, p2, p3]),
                             top.And([p1, p2])]), top.Transition('main', '4'))
                ], 'PRIMARY'),
            top.ProcedureStep('4', top.StateChangeAction('vent_valve', 'open'),
                              [], 'PRIMARY')
        ])
    ])

    assert suite == expected_suite
示例#10
0
def test_parse_two_procedures():
    proclang = '''
    main:
        1. PRIMARY: set injector_valve to open
        2. PRIMARY: set vent_valve to closed

    abort:
        1. PRIMARY: set injector_valve to closed
        2. PRIMARY: set vent_valve to open
    '''
    suite = top.proclang.parse(proclang)

    expected_suite = top.ProcedureSuite([
        top.Procedure('main', [
            top.ProcedureStep(
                '1', top.StateChangeAction('injector_valve', 'open'),
                [(top.Immediate(), top.Transition('main', '2'))], 'PRIMARY'),
            top.ProcedureStep('2', top.StateChangeAction(
                'vent_valve', 'closed'), [], 'PRIMARY')
        ]),
        top.Procedure('abort', [
            top.ProcedureStep(
                '1', top.StateChangeAction('injector_valve', 'closed'),
                [(top.Immediate(), top.Transition('abort', '2'))], 'PRIMARY'),
            top.ProcedureStep('2', top.StateChangeAction('vent_valve', 'open'),
                              [], 'PRIMARY')
        ])
    ])

    assert suite == expected_suite
示例#11
0
def test_proc_bridge_procedure_step_affects_plumbing():
    plumb_b = PlumbingBridge()
    control_b = ControlsBridge(plumb_b)
    proc_b = ProceduresBridge(plumb_b, control_b)

    procedure = top.Procedure('main', [
        top.ProcedureStep('1', top.StateChangeAction('injector_valve', 'open'),
                          [(top.Immediate(), top.Transition('main', '2'))],
                          'PRIMARY'),
        top.ProcedureStep(
            '2', top.StateChangeAction('injector_valve', 'closed'),
            [(top.Immediate(), top.Transition('main', '3'))], 'PRIMARY'),
        top.ProcedureStep('3', top.MiscAction('Approach the launch tower'), [],
                          'SECONDARY')
    ])
    proc_b.load_suite(top.ProcedureSuite([procedure]))

    plumb_eng = make_plumbing_engine()
    plumb_b.load_engine(plumb_eng)

    assert plumb_eng.current_state('injector_valve') == 'closed'
    proc_b.procStepForward()
    assert plumb_eng.current_state('injector_valve') == 'open'
    proc_b.procStepForward()
    assert plumb_eng.current_state('injector_valve') == 'closed'
示例#12
0
def test_proc_bridge_procedure_controls_advance_procedure():
    plumb_b = MockPlumbingBridge()
    proc_b = ProceduresBridge(plumb_b)

    procedure = top.Procedure('main', [
        top.ProcedureStep('1', top.StateChangeAction('injector_valve', 'open'),
                          [(top.Immediate(), top.Transition('main', '2'))],
                          'PRIMARY'),
        top.ProcedureStep('2', top.StateChangeAction('vent_valve', 'closed'), [
            (top.WaitFor(100), top.Transition('main', '3'))
        ], 'PRIMARY'),
        top.ProcedureStep('3', top.MiscAction('Approach the launch tower'), [],
                          'SECONDARY')
    ])

    proc_b.load_suite(top.ProcedureSuite([procedure]))

    proc_eng = proc_b._proc_eng

    assert proc_eng.current_step == procedure.step_list[0]
    assert proc_eng.step_position == top.StepPosition.Before
    proc_b.procStepForward()
    assert proc_eng.current_step == procedure.step_list[0]
    assert proc_eng.step_position == top.StepPosition.After
    proc_b.procStepForward()
    assert proc_eng.current_step == procedure.step_list[1]
    assert proc_eng.step_position == top.StepPosition.After
    proc_b.procStepForward()  # does nothing; condition is not satisfied
    assert proc_eng.current_step == procedure.step_list[1]
    assert proc_eng.step_position == top.StepPosition.After
    proc_b.procStop()
    assert proc_eng.current_step == procedure.step_list[0]
    assert proc_eng.step_position == top.StepPosition.Before
示例#13
0
def test_procedure_step_list():
    s1 = top.ProcedureStep('s1', None, [], 'PRIMARY')
    s2 = top.ProcedureStep('s2', None, [], 'PRIMARY')
    s3 = top.ProcedureStep('s3', None, [], 'PRIMARY')

    proc = top.Procedure('p1', [s1, s2, s3])

    assert proc.step_list == [s1, s2, s3]
示例#14
0
def test_procedure_builds_steps():
    s1 = top.ProcedureStep('s1', None, [], 'PRIMARY')
    s2 = top.ProcedureStep('s2', None, [], 'PRIMARY')
    s3 = top.ProcedureStep('s3', None, [], 'PRIMARY')

    proc = top.Procedure('p1', [s1, s2, s3])

    assert proc.steps == {'s1': s1, 's2': s2, 's3': s3}
示例#15
0
def test_procedure_equality_equal():
    s1 = top.ProcedureStep('s1', None, [], 'PRIMARY')
    s2 = top.ProcedureStep('s2', None, [], 'PRIMARY')
    s3 = top.ProcedureStep('s3', None, [], 'PRIMARY')

    proc_1 = top.Procedure('p1', [s1, s2, s3])
    proc_2 = top.Procedure('p1', [s1, s2, s3])

    assert proc_1 == proc_2
示例#16
0
def test_procedure_equality_different_steps():
    s1 = top.ProcedureStep('s1', None, [], 'PRIMARY')
    s2 = top.ProcedureStep('s2', None, [], 'PRIMARY')
    s3 = top.ProcedureStep('s3', None, [], 'PRIMARY')

    proc_1 = top.Procedure('p1', [s1, s2])
    proc_2 = top.Procedure('p1', [s1, s3])

    assert proc_1 != proc_2
示例#17
0
def test_procedure_suite_invalid_starting_procedure_errors():
    s1 = top.ProcedureStep('s1', None, [], 'PRIMARY')
    s2 = top.ProcedureStep('s2', None, [], 'PRIMARY')
    s3 = top.ProcedureStep('s3', None, [], 'PRIMARY')

    p1 = top.Procedure('p1', [s1, s2, s3])

    with pytest.raises(Exception):
        top.ProcedureSuite([p1], 'p2')
示例#18
0
def test_procedure_equality_different_type():
    s1 = top.ProcedureStep('s1', None, [], 'PRIMARY')
    s2 = top.ProcedureStep('s2', None, [], 'PRIMARY')
    s3 = top.ProcedureStep('s3', None, [], 'PRIMARY')

    proc_1 = top.Procedure('p1', [s1, s2, s3])

    assert proc_1 != 'proc_1'
    assert proc_1 != 10
    assert proc_1 is not None
示例#19
0
def test_procedure_index_of():
    s1 = top.ProcedureStep('s1', None, [], 'PRIMARY')
    s2 = top.ProcedureStep('s2', None, [], 'PRIMARY')
    s3 = top.ProcedureStep('s3', None, [], 'PRIMARY')

    proc = top.Procedure('p1', [s1, s2, s3])

    assert proc.index_of('s1') == 0
    assert proc.index_of('s2') == 1
    assert proc.index_of('s3') == 2
示例#20
0
def test_procedure_suite_duplicate_name_errors():
    s1 = top.ProcedureStep('s1', None, [], 'PRIMARY')
    s2 = top.ProcedureStep('s2', None, [], 'PRIMARY')
    s3 = top.ProcedureStep('s3', None, [], 'PRIMARY')

    proc_1 = top.Procedure('p1', [s1, s2])
    proc_2 = top.Procedure('p1', [s1, s3])

    with pytest.raises(Exception):
        top.ProcedureSuite([proc_1, proc_2])
示例#21
0
def test_procedure_suite_defaults_to_main():
    s1 = top.ProcedureStep('s1', None, [], 'PRIMARY')
    s2 = top.ProcedureStep('s2', None, [], 'PRIMARY')
    s3 = top.ProcedureStep('s3', None, [], 'PRIMARY')

    main = top.Procedure('main', [s1, s2, s3])
    not_main = top.Procedure('not_main', [s1, s2, s3])

    suite = top.ProcedureSuite([main, not_main])
    assert suite.starting_procedure_id == 'main'
示例#22
0
def test_procedure_suite_indexing():
    s1 = top.ProcedureStep('s1', None, [], 'PRIMARY')
    s2 = top.ProcedureStep('s2', None, [], 'PRIMARY')
    s3 = top.ProcedureStep('s3', None, [], 'PRIMARY')

    proc_1 = top.Procedure('p1', [s1, s2])
    proc_2 = top.Procedure('p2', [s1, s3])

    suite = top.ProcedureSuite([proc_1, proc_2], 'p1')

    assert suite['p1'] == proc_1
示例#23
0
def test_procedure_suite_builds_list():
    s1 = top.ProcedureStep('s1', None, [], 'PRIMARY')
    s2 = top.ProcedureStep('s2', None, [], 'PRIMARY')
    s3 = top.ProcedureStep('s3', None, [], 'PRIMARY')

    proc_1 = top.Procedure('p1', [s1, s2])
    proc_2 = top.Procedure('p2', [s1, s3])

    suite = top.ProcedureSuite([proc_1, proc_2], 'p1')

    assert suite.procedures == {'p1': proc_1, 'p2': proc_2}
示例#24
0
def single_procedure_suite():
    close_action = top.StateChangeAction('c1', 'closed')
    open_action = top.StateChangeAction('c1', 'open')

    s1 = top.ProcedureStep('s1', close_action,
                           [(top.Immediate(), top.Transition('p1', 's2'))],
                           'PRIMARY')
    s2 = top.ProcedureStep('s2', open_action, [], 'PRIMARY')

    proc = top.Procedure('p1', [s1, s2])

    return top.ProcedureSuite([proc], 'p1')
示例#25
0
def test_time_stop():
    plumb_b = PlumbingBridge()
    plumb_b.step_size = 0.1e6
    control_b = ControlsBridge(plumb_b)
    proc_b = ProceduresBridge(plumb_b, control_b)

    procedure = top.Procedure('main', [
        top.ProcedureStep('1', top.StateChangeAction('injector_valve', 'open'),
                          [(top.WaitFor(0.1e6), top.Transition('main', '2'))],
                          'PRIMARY'),
        top.ProcedureStep('2', top.MiscAction('Approach the launch tower'), [],
                          'SECONDARY')
    ])
    proc_b.load_suite(top.ProcedureSuite([procedure]))

    plumb_eng = make_plumbing_engine()
    plumb_b.load_engine(plumb_eng)

    proc_eng = proc_b._proc_eng

    proc_b.procStepForward()  # execute step 1
    assert not proc_eng.ready_to_proceed()
    # Time hasn't advanced yet, so pressures should be the same
    assert plumb_eng.current_pressures('A') == 100
    assert plumb_eng.current_pressures('B') == 0

    plumb_b.timeStepForward()  # time == 0.1s
    assert proc_eng.ready_to_proceed()
    # Valve is open, so pressures should start dropping
    assert plumb_eng.current_pressures('A') < 100
    assert plumb_eng.current_pressures('B') > 0

    proc_b.procStop()
    plumb_b.timeStop()

    # Everything should now be as it started

    assert proc_eng.current_step.step_id == '1'
    assert plumb_eng.current_state('injector_valve') == 'closed'
    assert plumb_eng.current_pressures('A') == 100
    assert plumb_eng.current_pressures('B') == 0

    proc_b.procStepForward()  # execute step 1
    assert not proc_eng.ready_to_proceed()
    # Time hasn't advanced yet, so pressures should be the same
    assert plumb_eng.current_pressures('A') == 100
    assert plumb_eng.current_pressures('B') == 0

    plumb_b.timeStepForward()  # time == 0.1s
    assert proc_eng.ready_to_proceed()
    # Valve is open, so pressures should start dropping
    assert plumb_eng.current_pressures('A') < 100
    assert plumb_eng.current_pressures('B') > 0
示例#26
0
def test_procedure_suite_equality_order_irrelevant():
    s1 = top.ProcedureStep('s1', None, [], 'PRIMARY')
    s2 = top.ProcedureStep('s2', None, [], 'PRIMARY')
    s3 = top.ProcedureStep('s3', None, [], 'PRIMARY')

    proc_1 = top.Procedure('p1', [s1, s2])
    proc_2 = top.Procedure('p2', [s1, s3])

    suite_1 = top.ProcedureSuite([proc_1, proc_2], 'p1')
    suite_2 = top.ProcedureSuite([proc_2, proc_1], 'p1')

    assert suite_1 == suite_2
示例#27
0
def test_procedure_suite_equality_different_procedures():
    s1 = top.ProcedureStep('s1', None, [], 'PRIMARY')
    s2 = top.ProcedureStep('s2', None, [], 'PRIMARY')
    s3 = top.ProcedureStep('s3', None, [], 'PRIMARY')

    proc_1 = top.Procedure('p1', [s1, s2])
    proc_2 = top.Procedure('p2', [s1, s3])

    suite_1 = top.ProcedureSuite([proc_1], 'p1')
    suite_2 = top.ProcedureSuite([proc_1, proc_2], 'p1')

    assert suite_1 != suite_2
示例#28
0
    def procedure(self, data):
        """
        Process `procedure` nodes in the parse tree.

        `data` is a list of the form [name, step0, step1, ...], where
        `name` is a string indicating the procedure ID and each `stepN`
        is a step_info dict generated by handling a `step` node.
        """
        name = data[0]
        steps = []

        # We optionally annotate each step with its entry condition (the
        # optional [p1 < 100] or [500s] before the step), and the
        # preceding step needs that information for its condition set.
        # In order to get that, we iterate over the steps in reverse
        # order and keep track of the most recently processed step, which
        # is the "successor" of the next step we will process.

        successor = None
        for step_info in data[-1:0:-1]:
            conditions = copy.deepcopy(step_info['conditions_out'])
            if successor is not None:
                conditions.append((successor['condition_in'],
                                   top.Transition(name, successor['id'])))
            successor = step_info
            new_step = top.ProcedureStep(step_info['id'], step_info['action'],
                                         conditions, step_info['personnel'])
            steps.insert(0, new_step)

        return top.Procedure(name, steps)
示例#29
0
def branching_procedure_suite_two_options():
    close_action = top.StateChangeAction('c1', 'closed')
    open_action = top.StateChangeAction('c1', 'open')
    halfway_open_action = top.StateChangeAction('c1', 'halfway_open')

    s1 = top.ProcedureStep('s1', close_action,
                           [(top.Immediate(), top.Transition('p1', 's2')),
                            (top.Immediate(), top.Transition('p2', 's3'))],
                           'PRIMARY')
    s2 = top.ProcedureStep('s2', halfway_open_action, {}, 'PRIMARY')
    s3 = top.ProcedureStep('s3', open_action, {}, 'PRIMARY')

    proc_1 = top.Procedure('p1', [s1, s2, s3])
    proc_2 = top.Procedure('p2', [s1, s2, s3])

    return top.ProcedureSuite([proc_1, proc_2], 'p1')
def test_steps_model_change_proc():
    model = ProcedureStepsModel()

    procedure = top.Procedure('main', [
        top.ProcedureStep('1', top.StateChangeAction('injector_valve', 'open'), [
            (top.Immediate(), top.Transition('main', '2'))
        ], 'PRIMARY'),
        top.ProcedureStep('2', top.StateChangeAction('vent_valve', 'closed'), [], 'SECONDARY')
    ])

    wrapper = ProcedureConditionWrapper(top.Immediate(), top.Transition('main', '2'))

    model.change_procedure(procedure)

    assert model.procedure == procedure
    assert model.condition_wrappers == [[wrapper], []]
    assert model.rowCount() == 2