예제 #1
0
def test_bad_infer_width_and_height(working_args):
    a = working_args.copy()
    del a["width"]
    with pytest.raises(TypeError):
        Machine(**a)

    a = working_args.copy()
    del a["height"]
    with pytest.raises(TypeError):
        Machine(**a)
예제 #2
0
def test_with_standard_ips():
    board_locations = {(x, y, z): (x, y, z)
                       for x in range(2) for y in range(2) for z in range(3)}

    m = Machine.with_standard_ips("m", board_locations=board_locations)

    assert m.bmp_ips == {
        (0, 0): "192.168.0.0",
        (0, 1): "192.168.1.0",
        (1, 0): "192.168.5.0",
        (1, 1): "192.168.6.0",
    }

    assert m.spinnaker_ips == {
        (0, 0, 0): "192.168.0.1",
        (0, 0, 1): "192.168.0.9",
        (0, 0, 2): "192.168.0.17",
        (0, 1, 0): "192.168.1.1",
        (0, 1, 1): "192.168.1.9",
        (0, 1, 2): "192.168.1.17",
        (1, 0, 0): "192.168.5.1",
        (1, 0, 1): "192.168.5.9",
        (1, 0, 2): "192.168.5.17",
        (1, 1, 0): "192.168.6.1",
        (1, 1, 1): "192.168.6.9",
        (1, 1, 2): "192.168.6.17",
    }
def test_with_standard_ips():
    board_locations = {(x, y, z): (x, y, z)
                       for x in range(2)
                       for y in range(2)
                       for z in range(3)}

    m = Machine.with_standard_ips("m", board_locations=board_locations)

    assert m.bmp_ips == {
        (0, 0): "192.168.0.0",
        (0, 1): "192.168.1.0",
        (1, 0): "192.168.5.0",
        (1, 1): "192.168.6.0",
    }

    assert m.spinnaker_ips == {
        (0, 0, 0): "192.168.0.1",
        (0, 0, 1): "192.168.0.9",
        (0, 0, 2): "192.168.0.17",

        (0, 1, 0): "192.168.1.1",
        (0, 1, 1): "192.168.1.9",
        (0, 1, 2): "192.168.1.17",

        (1, 0, 0): "192.168.5.1",
        (1, 0, 1): "192.168.5.9",
        (1, 0, 2): "192.168.5.17",

        (1, 1, 0): "192.168.6.1",
        (1, 1, 1): "192.168.6.9",
        (1, 1, 2): "192.168.6.17",
    }
예제 #4
0
def test_single_board():
    m = Machine.single_board("m", set(["default"]), "bmp", "spinn")
    assert m.name == "m"
    assert m.tags == set(["default"])
    assert m.width == 1
    assert m.height == 1
    assert m.dead_boards == set([(0, 0, 1), (0, 0, 2)])
    assert m.dead_links == set()
    assert m.board_locations == {(0, 0, 0): (0, 0, 0)}
    assert m.bmp_ips == {(0, 0): "bmp"}
    assert m.spinnaker_ips == {(0, 0, 0): "spinn"}
def test_single_board():
    m = Machine.single_board("m", set(["default"]), "bmp", "spinn")
    assert m.name == "m"
    assert m.tags == set(["default"])
    assert m.width == 1
    assert m.height == 1
    assert m.dead_boards == set([(0, 0, 1), (0, 0, 2)])
    assert m.dead_links == set()
    assert m.board_locations == {(0, 0, 0): (0, 0, 0)}
    assert m.bmp_ips == {(0, 0): "bmp"}
    assert m.spinnaker_ips == {(0, 0, 0): "spinn"}
예제 #6
0
def test_single_board_no_ip():
    with pytest.raises(TypeError):
        Machine.single_board("m", set(["default"]))
    with pytest.raises(TypeError):
        Machine.single_board("m", set(["default"]), bmp_ip="foo")
    with pytest.raises(TypeError):
        Machine.single_board("m", set(["default"]), spinnaker_ip="bar")
def test_single_board_no_ip():
    with pytest.raises(TypeError):
        Machine.single_board("m", set(["default"]))
    with pytest.raises(TypeError):
        Machine.single_board("m", set(["default"]), bmp_ip="foo")
    with pytest.raises(TypeError):
        Machine.single_board("m", set(["default"]), spinnaker_ip="bar")
def big_m_with_hole(conn):
    """Add a larger 4x2 machine to the controller with board (2, 1, 0) dead."""
    conn.machines = {
        "big_m":
        Machine.with_standard_ips(name="big_m",
                                  dead_boards=set([(2, 1, 0)]),
                                  board_locations={(x, y, z):
                                                   (x * 10, y * 10, z * 10)
                                                   for x in range(4)
                                                   for y in range(2)
                                                   for z in range(3)
                                                   if (x, y, z) != (2, 1, 0)}),
    }
    return "big_m"
예제 #9
0
def simple_machine(name, width=1, height=2, tags=set(["default"]),
                   dead_boards=None, dead_links=None, ip_prefix=""):
    """Construct a simple machine with nothing broken etc."""
    return Machine(name=name, tags=tags, width=width, height=height,
                   dead_boards=dead_boards or set(),
                   dead_links=dead_links or set(),
                   board_locations={(x, y, z): (x, y, z)
                                    for x in range(width)
                                    for y in range(height)
                                    for z in range(3)},
                   bmp_ips={(x, y): "{}10.1.{}.{}".format(ip_prefix, x, y)
                            for x in range(width)
                            for y in range(height)},
                   spinnaker_ips={(x, y, z): "{}11.{}.{}.{}".format(
                                      ip_prefix, x, y, z)
                                  for x in range(width)
                                  for y in range(height)
                                  for z in range(3)})
def test_with_standard_ips_bad_ias():
    board_locations = {(x, y, z): (x, y, z)
                       for x in range(2)
                       for y in range(2)
                       for z in range(3)}

    # Not IPv4 address
    with pytest.raises(ValueError):
        Machine.with_standard_ips("m", board_locations=board_locations,
                                  base_ip="spinn-4")

    # Malformed IPv4 addresses
    with pytest.raises(ValueError):
        Machine.with_standard_ips("m", board_locations=board_locations,
                                  base_ip="1.2.3")
    with pytest.raises(ValueError):
        Machine.with_standard_ips("m", board_locations=board_locations,
                                  base_ip="-1.2.3.4")
    with pytest.raises(ValueError):
        Machine.with_standard_ips("m", board_locations=board_locations,
                                  base_ip="256.2.3.4")
예제 #11
0
def test_machine(name="m", bmp_prefix=None, spinnaker_prefix=None):
    """A minimal set of valid arguments for a Machine's constructor."""
    bmp_prefix = bmp_prefix or "bmp_{}".format(name)
    spinnaker_prefix = spinnaker_prefix or "spinn_{}".format(name)
    return Machine(
        name=name,
        tags=set("default"),
        width=2,
        height=1,
        dead_boards=set(),
        dead_links=set(),
        board_locations={(x, y, z): (x * 10, y * 10, z * 10)
                         for x in range(2) for y in range(1)
                         for z in range(3)},
        bmp_ips={(c * 10, f * 10): "{}_{}_{}".format(bmp_prefix, c, f)
                 for c in range(2) for f in range(1)},
        spinnaker_ips={(x, y, z): "{}_{}_{}_{}".format(spinnaker_prefix, x, y,
                                                       z)
                       for x in range(2) for y in range(1) for z in range(3)},
    )
예제 #12
0
def test_with_standard_ips_bad_ias():
    board_locations = {(x, y, z): (x, y, z)
                       for x in range(2) for y in range(2) for z in range(3)}

    # Not IPv4 address
    with pytest.raises(ValueError):
        Machine.with_standard_ips("m",
                                  board_locations=board_locations,
                                  base_ip="spinn-4")

    # Malformed IPv4 addresses
    with pytest.raises(ValueError):
        Machine.with_standard_ips("m",
                                  board_locations=board_locations,
                                  base_ip="1.2.3")
    with pytest.raises(ValueError):
        Machine.with_standard_ips("m",
                                  board_locations=board_locations,
                                  base_ip="-1.2.3.4")
    with pytest.raises(ValueError):
        Machine.with_standard_ips("m",
                                  board_locations=board_locations,
                                  base_ip="256.2.3.4")
예제 #13
0
def test_bad_dead_links(working_args, x, y, z):
    # If any links are out of range, should fail
    working_args["dead_links"].add((x, y, z, Links.north))
    with pytest.raises(ValueError):
        Machine(**working_args)
예제 #14
0
def test_valid_args(working_args):
    # Should not fail to validate something valid
    Machine(**working_args)
def test_controller_set_machines(conn, mock_abc):
    # Test the ability to add machines

    # Create a set of machines
    machines = OrderedDict()
    for num in range(3):
        m = Machine(name="m{}".format(num),
                    tags=set(["default", "num{}".format(num)]),
                    width=1 + num,
                    height=2,
                    dead_boards=set([(0, 0, 1)]),
                    dead_links=set([(0, 0, 2, Links.north)]),
                    board_locations={(x, y, z): (x * 10, y * 10, z * 10)
                                     for x in range(1 + num) for y in range(2)
                                     for z in range(3)},
                    bmp_ips={(c * 10, f * 10): "10.1.{}.{}".format(c, f)
                             for c in range(1 + num) for f in range(2)},
                    spinnaker_ips={(x, y, z): "11.{}.{}.{}".format(x, y, z)
                                   for x in range(1 + num) for y in range(2)
                                   for z in range(3)})
        machines[m.name] = m
    m0 = machines["m0"]
    m1 = machines["m1"]
    m2 = machines["m2"]

    # Special case: Setting no machines should not break anything
    machines = OrderedDict()
    conn.machines = machines
    assert len(conn._machines) == 0
    assert len(conn._job_queue._machines) == 0
    assert len(conn._bmp_controllers) == 0
    assert mock_abc.running_theads == 0

    # Try adding a pair of machines
    machines["m1"] = m1
    machines["m0"] = m0
    conn.machines = machines

    # Check that the set of machines copies across
    assert conn._machines == machines

    # Make sure things are passed into the job queue correctly
    assert list(conn._job_queue._machines) == ["m1", "m0"]
    assert conn._job_queue._machines["m0"].tags == m0.tags
    assert conn._job_queue._machines["m0"].allocator.dead_boards \
        == m0.dead_boards
    assert conn._job_queue._machines["m0"].allocator.dead_links \
        == m0.dead_links

    assert conn._job_queue._machines["m1"].tags == m1.tags
    assert conn._job_queue._machines["m1"].allocator.dead_boards \
        == m1.dead_boards
    assert conn._job_queue._machines["m1"].allocator.dead_links \
        == m1.dead_links

    # Make sure BMP controllers are spun-up correctly
    assert len(conn._bmp_controllers) == 2
    assert len(conn._bmp_controllers["m0"]) == m0.width * m0.height
    assert len(conn._bmp_controllers["m1"]) == m1.width * m1.height
    for m_name, controllers in conn._bmp_controllers.items():
        for c in range(machines[m_name].width):
            for f in range(machines[m_name].height):
                assert controllers[(c*10, f*10)].hostname \
                    == "10.1.{}.{}".format(c, f)
    assert mock_abc.running_theads == mock_abc.num_created == (
        (m1.width * m1.height) + (m0.width * m0.height))

    # If we pass in the same machines in, nothing should get changed
    conn.machines = machines
    assert conn._machines == machines
    assert list(conn._job_queue._machines) == list(machines)
    assert mock_abc.running_theads == mock_abc.num_created == (
        (m1.width * m1.height) + (m0.width * m0.height))

    # If we pass in the same machines in a different order, the order should
    # change but nothing should get spun up/down
    machines = OrderedDict()
    machines["m0"] = m0
    machines["m1"] = m1
    conn.machines = machines
    assert conn._machines == machines
    assert list(conn._job_queue._machines) == list(machines)
    assert mock_abc.running_theads == mock_abc.num_created == (
        (m1.width * m1.height) + (m0.width * m0.height))

    # Adding a new machine should spin just one new machine up leaving the
    # others unchanged
    machines = OrderedDict()
    machines["m0"] = m0
    machines["m1"] = m1
    machines["m2"] = m2
    conn.machines = machines
    assert conn._machines == machines
    assert list(conn._job_queue._machines) == list(machines)
    assert mock_abc.running_theads == mock_abc.num_created == (
        m2.width * m2.height + m1.width * m1.height + m0.width * m0.height)

    # Modifying a machine in minor ways: should not respin anything but the
    # change should be applied
    m0 = Machine(name=m0.name,
                 tags=set(["new tags"]),
                 width=m0.width,
                 height=m0.height,
                 dead_boards=set([(0, 0, 0)]),
                 dead_links=set([(0, 0, 0, Links.south)]),
                 board_locations=m0.board_locations,
                 bmp_ips=m0.bmp_ips,
                 spinnaker_ips=m0.spinnaker_ips)
    machines["m0"] = m0
    conn.machines = machines

    # Machine list should be updated
    assert conn._machines == machines

    # Job queue should be updated
    assert list(conn._job_queue._machines) == list(machines)
    assert conn._job_queue._machines["m0"].tags == set(["new tags"])
    assert conn._job_queue._machines["m0"].allocator.dead_boards \
        == set([(0, 0, 0)])
    assert conn._job_queue._machines["m0"].allocator.dead_links \
        == set([(0, 0, 0, Links.south)])

    # Nothing should be spun up
    assert mock_abc.running_theads == mock_abc.num_created == (
        m2.width * m2.height + m1.width * m1.height + m0.width * m0.height)

    # Removing a machine should result in things being spun down
    del machines["m0"]
    conn.machines = machines

    # Machine list should be updated
    assert conn._machines == machines

    # Job queue should be updated
    assert list(conn._job_queue._machines) == list(machines)

    # Some BMPs should now be shut down
    time.sleep(0.05)
    assert mock_abc.running_theads == ((m2.width * m2.height) +
                                       (m1.width * m1.height))

    # Nothing new should be spun up
    assert mock_abc.num_created == (m2.width * m2.height +
                                    m1.width * m1.height +
                                    m0.width * m0.height)

    # Making any significant change to a machine should result in it being
    # re-spun.
    m1 = Machine(
        name=m1.name,
        tags=m1.tags,
        width=m1.width - 1,  # A significant change(!)
        height=m1.height,
        dead_boards=m1.dead_boards,
        dead_links=m1.dead_links,
        board_locations=m0.board_locations,
        bmp_ips=m0.bmp_ips,
        spinnaker_ips=m0.spinnaker_ips)
    machines["m1"] = m1

    m1_alloc_before = conn._job_queue._machines["m1"].allocator
    m2_alloc_before = conn._job_queue._machines["m2"].allocator

    conn.machines = machines

    m1_alloc_after = conn._job_queue._machines["m1"].allocator
    m2_alloc_after = conn._job_queue._machines["m2"].allocator

    # Machine list should be updated
    assert conn._machines == machines
    time.sleep(0.05)

    # Job queue should be updated and a new allocator etc. made for the new
    # machine
    assert list(conn._job_queue._machines) == list(machines)
    assert m1_alloc_before is not m1_alloc_after
    assert m2_alloc_before is m2_alloc_after

    # Same number of BMPs should be up
    assert mock_abc.running_theads == ((m2.width * m2.height) +
                                       (m1.width * m1.height))

    # But a new M1 should be spun up
    assert mock_abc.num_created == ((m2.width * m2.height) +
                                    ((m1.width + 1) * m1.height) +
                                    (m1.width * m1.height) +
                                    (m0.width * m0.height))
예제 #16
0
def test_bad_dead_boards_type(working_args):
    working_args["dead_boards"] = [(0, 0, 0)]
    with pytest.raises(TypeError):
        Machine(**working_args)
예제 #17
0
def test_bad_tags(working_args):
    working_args["tags"] = ["foo"]
    with pytest.raises(TypeError):
        Machine(**working_args)
예제 #18
0
def test_spinnaker_ips_defined(working_args):
    # All boards whose location is specified should have a BMP IP
    del working_args["spinnaker_ips"][(0, 0, 0)]
    with pytest.raises(ValueError):
        Machine(**working_args)
예제 #19
0
def test_infer_width_and_height(working_args):
    del working_args["width"]
    del working_args["height"]
    m = Machine(**working_args)
    assert m.width == 2
    assert m.height == 1
예제 #20
0
def test_board_locations_defined(working_args):
    # If any live board locations are not given, we should fail. We reomve a
    # dead board whose location is otherwise not set
    working_args["dead_boards"].clear()
    with pytest.raises(ValueError):
        Machine(**working_args)
예제 #21
0
def test_board_locations_no_duplicates(working_args):
    # No two boards should have the same location
    working_args["board_locations"][(0, 0, 0)] = (0, 0, 0)
    working_args["board_locations"][(0, 0, 1)] = (0, 0, 0)
    with pytest.raises(ValueError):
        Machine(**working_args)
예제 #22
0
def test_board_locations_in_machine(working_args, x, y, z):
    # If any live board locations are given for boards outside the system, we
    # should fail
    working_args["board_locations"][(x, y, z)] = (100, 100, 100)
    with pytest.raises(ValueError):
        Machine(**working_args)
예제 #23
0
def test_bad_dead_links_type(working_args):
    working_args["dead_links"] = [(0, 0, 0, Links.north)]
    with pytest.raises(TypeError):
        Machine(**working_args)
예제 #24
0
def test_bad_dead_boards(working_args, x, y, z):
    # If any boards are out of range, should fail
    working_args["dead_boards"].add((x, y, z))
    with pytest.raises(ValueError):
        Machine(**working_args)