示例#1
0
def test_here_single(device, config, name, usrparam=None, dry_run=DRY_RUN):
    """Test a configuration sequence.

    Args:
        device: device fixture
        config[]: map of all config chunks:
            config[n][0]: first part of config chunk
            config[n][1]: second part of config chunk
            config[n][n]: last part of config chunk
        name: name of config chunk to run
    Returns:
        nothing

    Given the input ["set A 1
                      set A 2",
                     "set B 1
                      set B 2"]
    the test will run the following CLI commands:
        (a)
        set A 1
        set A 2  # commit - compare
        (b)
        set B 1
        set B 2  # commit - compare
        (c)
        rollback to (a) - compare
        rollback to (c) - compare
        rollback to (b) - compare
        rollback to (a) - compare
    """
    device.save("drned-work/before-test.cfg")
    commit_id_base = len(device.commit_id)
    # Handle all chunks
    settings = Settings()
    try:
        try:
            for i,conf in enumerate(config[name]):
                _chunk_part(device, i, name, conf, usrparam=usrparam,
                            settings=settings, dry_run=dry_run,
                            operations=["load", "commit", "compare-config"])
        except StopIteration:
            device.sync_from()
            rollback_to_start(device, commit_id_base, dry_run)
        except:
            rollback_to_start(device, commit_id_base, dry_run)
            raise
        else:
            rollback_to_start(device, commit_id_base, dry_run)
            # Rollback to end, and then incrementally to start again
            for i in reversed(range(commit_id_base, len(device.commit_id))):
                device.rollback_compare(id=device.commit_id[i], dry_run=dry_run)
    finally:
        settings.restore_all()
        # Test that we're back
        device.save("drned-work/after-test.cfg")
        if not common.filecmp("drned-work/before-test.cfg",
                              "drned-work/after-test.cfg"):
            pytest.fail("The state after rollback differs from before load. " +
                        "Please check before-test.cfg and after-test.cfg")
示例#2
0
def _here_union(device, config, it, dry_run=False):
    device.save("drned-work/before-test.cfg")
    names = sorted(config.keys())
    if it in [2, 4, 6]:
        names = reversed(names)
    commit_id_base = len(device.commit_id)
    settings = Settings()
    try:
        try:
            for name in names:
                device.trace("\npy.test -k 'test_here_single[%s]'\n" % name)
                # Commit loop
                for i, conf in enumerate(config[name]):
                    if it in [1, 2]:
                        operations = ["load", "commit", "compare-config"]
                    else:
                        operations = ["load"]
                    _chunk_part(device,
                                i,
                                name,
                                conf,
                                settings=settings,
                                dry_run=dry_run,
                                operations=operations,
                                do_functions=False)
                if it in [3, 4]:
                    device.commit_compare(dry_run=dry_run)
            if it in [5, 6]:
                device.commit_compare(dry_run=dry_run)
        except StopIteration:
            device.sync_from()
            rollback_to_start(device, commit_id_base, dry_run)
        except Exception:
            rollback_to_start(device, commit_id_base, dry_run)
            raise
        else:
            rollback_to_start(device, commit_id_base, dry_run)
            # Rollback to end, and then incrementally to start again
            for i in reversed(range(commit_id_base, len(device.commit_id))):
                device.rollback_compare(id=device.commit_id[i],
                                        dry_run=dry_run)
    finally:
        settings.restore_all()
        # Test that we're back
        device.save("drned-work/after-test.cfg")
        if not common.filecmp("drned-work/before-test.cfg",
                              "drned-work/after-test.cfg"):
            pytest.fail("The state after rollback differs from before load. " +
                        "Please check before-test.cfg and after-test.cfg")
示例#3
0
def test_template_single(device, template, op):
    """Normal test with template file.

    The rollback[+-no] operation specifies an index in a list of all
    commits that have been performed in this function. This means that
    rollback-1 will undo the last commit, rollback+0 will undo all
    commits, etc.

    The operations to perform can also be specified either in the
    template file itself, or in a .load file (see Device.load). An
    example of the template file syntax:

    !op=(load,commit)

    This test is using the device fixture, which means that the device
    state is restored after test.

    Args:
        device: device fixture
        template: name of the template file
        op[0..n]: operations to be performed:
            "":             no-op
            load:           load file
            commit:         commit configuration
            compare-config: compare configuration
            check-sync:     check that device is in sync
            rollback[+-no]: rollback configuration
            Default: ["load", "commit", "compare-config",
                      "rollback", "commit", "compare-config"]
    Returns:
        nothing

    """
    if op is None:
        op = ["load", "commit", "compare-config",
              "rollback", "commit", "compare-config"]
    device.save("drned-work/before-test.cfg")
    src,_,_ = _drned_single_file(device, template, op)
    device.save("drned-work/after-test.cfg")
    if not src and not common.filecmp("drned-work/before-test.cfg",
                                      "drned-work/after-test.cfg"):
        pytest.fail("The state after rollback differs from before load. " +
                    "Please check before-test.cfg and after-test.cfg")
示例#4
0
def device(request):
    devname = request.config.getoption("--device")
    if devname == None:
        pytest.fail("Please enter a device name using the --device " +
                    "command-line parameter")
    # Time to create device
    use = request.config.getoption("--use")
    device = drned.Device(devname, use=use, request=request)
    device.trace("\n%s\n" % request._pyfuncitem.name)
    # Save state in XML to be able to restore
    # reliably. Note that the entire "devices" tree is
    # saved, the "replace" load option requires it.
    device.save("drned-work/before-session.xml",
                path="devices", fmt="xml")
    # Also save in CLI format to make it easier to
    # compare
    device.save("drned-work/before-session.cfg")
    yield device
    print("\n### TEARDOWN, RESTORE DEVICE ###")
    device.reset_cli()
    # Try to restore device twice, required for some NCS releases
    laps = 2
    for i in range(laps):
        device.sync_from()
        device.load("drned-work/before-session.xml", mode="replace")
        device.commit()
        try:
            device.compare_config()
            break
        except pytest.fail.Exception as e:
            if i >= (laps - 1):
                raise
    # Check if restore successful
    device.save("drned-work/after-session.cfg")
    if not common.filecmp("drned-work/before-session.cfg",
                          "drned-work/after-session.cfg"):
        pytest.fail("Could not restore device to state before session. " +
                    "Please check before-session.cfg and after-session.cfg")
示例#5
0
def _drned_single_set(device, init, fname, init_op, op, end_op, it, ordered):
    src_in_set = False
    device.save("drned-work/before-test.cfg")
    # Load init files
    init_id_start = len(device.commit_id)
    if init is not None:
        if init_op is None:
            init_op = ["load", "commit", "compare-config"]
        for init_file in init:
            src,_,_ = _drned_single_file(device, init_file, init_op)
            src_in_set = src_in_set or src
    init_id_stop = len(device.commit_id)
    # Must at least have one file
    if not fname:
        pytest.fail("Please specify a file with the --fname option")
    # Divide in sets
    file_sets = [re.sub(r":[^\.]*", ":*", f) for f in fname]
    if ordered == "true":
        tsets = sorted(list(set(file_sets)))
    else:
        # need to preserve the tset order, but remove duplicities
        t_set = set()
        tsets = []
        for fset in file_sets:
            if fset not in t_set:
                tsets.append(fset)
                t_set.add(fset)
    if not it % 2:
        tsets = reversed(tsets)
    if op is None:
        op = ["load", "commit", "compare-config"]
    pinit = " --init=" + " --init=".join(init) if init else ""
    piop = " --init-op=" + " --init-op=".join(init_op) if init_op else ""
    pop = " --op=" + " --op=".join(op) if op else ""
    peop = " --end-op=" + " --end-op=".join(end_op) if end_op else ""
    # Loop for sets
    for tset in tsets:
        device.trace("\npy.test -k test_template_set%s " % (pinit) +
                     "--fname=%s%s%s%s --device=%s\n" %
                     (tset, piop, pop, peop, device.name))
        commit_id_base = len(device.commit_id)
        tset_files = sorted(glob.glob(tset))
        set_all_operation = True
        # Use upper scheme as default
        the_end = end_op
        try:
            for tset_file in tset_files:
                src,eop,sop = _drned_single_file(device, tset_file, op)
                src_in_set = src_in_set or src
                set_all_operation = set_all_operation and sop
                # Get end operations from file, if present
                if eop:
                    # File operations override
                    the_end = eop

            if the_end == None:
                # Default action is to first rollback to start, then to
                # end, then rollback all commits, one by one
                if set_all_operation:
                    the_end = ["rollback+0", "commit", "compare-config"]
                    extra_rollback = 1
                else:
                    the_end = []
                    extra_rollback = 0
                for i in reversed(range(commit_id_base, len(device.commit_id) + extra_rollback)):
                    the_end += ["rollback+%d" % (i - commit_id_base), "commit", "compare-config"]
            # Use the file function also for rollbacks
            _drned_single_file(device, None, the_end,
                               commit_id_base=commit_id_base)
        except KeyboardInterrupt:
            # do not intercept CTRL-C
            raise
        except BaseException:
            # Record the failed state and, if this is not the last
            # state in the list, restore the device to its original
            # configuration and continue testing. If this is the last
            # test, re-raise the exception and trigger regular
            # cleanup/error reporting.
            m = re.match(r".*/(\S*).state.(cfg|xml)", tset)
            device.failed_states.append(m.group(1))
            if tset != tsets[-1]:
                # Re-raise walk states error to trigger error condition.
                device.restore()
            else:
                raise
            continue

    # Rollback init files
    for i in reversed(range(init_id_start, init_id_stop)):
        device.rollback_compare(id=device.commit_id[i], dry_run=False)
    # Check that we're back
    device.save("drned-work/after-test.cfg")
    if not src_in_set and end_op is None \
       and not common.filecmp("drned-work/before-test.cfg",
                              "drned-work/after-test.cfg"):
        pytest.fail("The state after rollback differs from before load. " +
                    "Please check before-test.cfg and after-test.cfg")
示例#6
0
def _drned_single_set(device, init, fname, init_op, op, end_op, it, ordered):
    src_in_set = False
    device.save("drned-work/before-test.cfg")
    # Load init files
    init_id_start = len(device.commit_id)
    if init != None:
        if init_op == None:
            init_op = ["load", "commit", "compare-config"]
        for init_file in init:
            src,_,_ = _drned_single_file(device, init_file, init_op)
            src_in_set = src_in_set or src
    init_id_stop = len(device.commit_id)
    # Must at least have one file
    if not fname:
        pytest.fail("Please specify a file with the --fname option")
    # Divide in sets
    tsets = [re.sub(":[^\.]*", ":*", f) for f in fname]
    if ordered == "true":
        tsets = sorted(list(set(tsets)))
    if not it % 2:
        tsets = reversed(tsets)
    if op == None:
        op = ["load", "commit", "compare-config"]
    pinit = " --init=" + " --init=".join(init) if init else ""
    piop = " --init-op=" + " --init-op=".join(init_op) if init_op else ""
    pop = " --op=" + " --op=".join(op) if op else ""
    peop = " --end-op=" + " --end-op=".join(end_op) if end_op else ""
    # Loop for sets
    for tset in tsets:
        device.trace("\npy.test -k test_template_set%s " % (pinit) +
                     "--fname=%s%s%s%s --device=%s\n" %
                     (tset, piop, pop, peop, device.name))
        commit_id_base = len(device.commit_id)
        tset_files = sorted(glob.glob(tset))
        set_all_operation = True
        # Use upper scheme as default
        the_end = end_op
        for tset_file in tset_files:
            src,eop,sop = _drned_single_file(device, tset_file, op)
            src_in_set = src_in_set or src
            set_all_operation = set_all_operation and sop
            # Get end operations from file, if present
            if eop:
                # File operations override
                the_end = eop
        if the_end == None:
            # Default action is to first rollback to start, then to
            # end, then rollback all commits, one by one
            if set_all_operation:
                the_end = ["rollback+0", "commit", "compare-config"]
                extra_rollback = 1
            else:
                the_end = []
                extra_rollback = 0
            for i in reversed(range(commit_id_base, len(device.commit_id) + extra_rollback)):
                the_end += ["rollback+%d" % (i - commit_id_base), "commit", "compare-config"]
        # Use the file function also for rollbacks
        _drned_single_file(device, None, the_end,
                           commit_id_base=commit_id_base)
    # Rollback init files
    for i in reversed(range(init_id_start, init_id_stop)):
        device.rollback_compare(id=device.commit_id[i], dry_run=False)
    # Check that we're back
    device.save("drned-work/after-test.cfg")
    if not src_in_set and end_op == None \
       and not common.filecmp("drned-work/before-test.cfg",
                              "drned-work/after-test.cfg"):
        pytest.fail("The state after rollback differs from before load. " +
                    "Please check before-test.cfg and after-test.cfg")