Exemplo n.º 1
0
def test_add(helpers, pcs_full, valid_profile_pool):
    """Test calling 'perun add profile hash', i.e. basic functionality

    Expecting no error. Profile is added to the repository, and to the index, to the specified
    minor version.
    """
    git_repo = git.Repo(os.path.split(pcs_full.path)[0])
    commits = [binascii.hexlify(c.binsha).decode('utf-8') for c in git_repo.iter_commits()]
    current_head = commits[0]
    before_count = helpers.count_contents_on_path(pcs_full.path)
    obj_path = pcs_full.path

    # First valid profile should be mapped to the same chunk
    for valid_profile in valid_profile_pool:
        valid_profile = helpers.prepare_profile(pcs_full, valid_profile, current_head)
        # Check that the profile was NOT in the index before
        before_entries_count = assert_before_add(helpers, obj_path, current_head, valid_profile)

        # Add the profile to timestamp
        commands.add([valid_profile], current_head, keep_profile=True)

        # Now check, that the profile was successfully added to index, and its entry is valid
        after_entries_count = assert_after_valid_add(helpers, obj_path, current_head, valid_profile)
        assert before_entries_count == (after_entries_count - 1)

    # Assert that just len-1 blobs was added, as the second profile has the same structure as
    #   one of the profiles already in the tracking
    after_count = helpers.count_contents_on_path(pcs_full.path)
    assert before_count[1] == (after_count[1] - (len(valid_profile_pool) - 1))
Exemplo n.º 2
0
def test_add_no_minor(helpers, pcs_full, valid_profile_pool):
    """Test calling 'perun add profile hash' without specified minor version

    Expecting no error. Profiles are added to the repository, and to the index, to the head.

    Fixme: Extend with more checks
    """
    git_repo = git.Repo(os.path.split(pcs_full.path)[0])
    head = str(git_repo.head.commit)
    before_count = helpers.count_contents_on_path(pcs_full.path)
    obj_path = pcs_full.path

    for valid_profile in valid_profile_pool:
        valid_profile = helpers.prepare_profile(pcs_full, valid_profile, head)
        # Check that the profile was NOT in the index before
        before_entries_count = assert_before_add(helpers, obj_path, head, valid_profile)

        commands.add([valid_profile], None, keep_profile=True)

        # Now check, that the profile was successfully added to index, and its entry is valid
        after_entries_count = assert_after_valid_add(helpers, obj_path, head, valid_profile)
        assert before_entries_count == (after_entries_count - 1)

    # Assert that just len-1 blobs was added, as the second profile has the same structure as
    #   one of the profiles already in the tracking
    after_count = helpers.count_contents_on_path(pcs_full.path)
    assert before_count[1] == (after_count[1] - (len(valid_profile_pool) - 1))
Exemplo n.º 3
0
def test_add_wrong_profile(helpers, pcs_full, error_profile_pool, capsys):
    """Test calling 'perun add profile hash' with profile in wrong format

    Expecting raising an exception, that the profile is wrong.
    """
    git_repo = git.Repo(os.path.split(pcs_full.get_path())[0])
    head = str(git_repo.head.commit)
    before_count = helpers.count_contents_on_path(pcs_full.get_path())

    for error_profile in error_profile_pool:
        before_entries_count = assert_before_add(helpers, pcs_full.get_path(),
                                                 head, error_profile)
        with pytest.raises(IncorrectProfileFormatException):
            commands.add([error_profile], None, keep_profile=True)

        # Assert that the profile was not added into the index
        after_entries_count = assert_after_invalid_add(helpers,
                                                       pcs_full.get_path(),
                                                       head, error_profile)
        assert before_entries_count == after_entries_count

    # Assert that nothing was added (rather weak, but should be enough)
    after_count = helpers.count_contents_on_path(pcs_full.get_path())
    assert before_count == after_count

    # Try to assert adding not existing profile
    with pytest.raises(SystemExit):
        commands.add(['notexisting.perf'], None, keep_profile=True)
    after_count = helpers.count_contents_on_path(pcs_full.get_path())
    assert before_count == after_count

    _, err = capsys.readouterr()
    assert "notexisting.perf does not exist" in err
Exemplo n.º 4
0
def test_add_outside_pcs(valid_profile_pool):
    """Test calling 'perun add outside of the scope of the PCS wrapper

    Expecting an exception NotPerunRepositoryException, as we are outside of the perun scope,
    and thus should not do anything, should be caught on the CLI/UI level
    """
    with pytest.raises(NotPerunRepositoryException):
        commands.add([valid_profile_pool[0]], None, keep_profile=True)
Exemplo n.º 5
0
def pcs_full():
    """
    Returns:
        PCS: object with performance control system, initialized with some files and stuff
    """
    # Change working dir into the temporary directory
    profiles = stored_profile_pool()
    pcs_path = tempfile.mkdtemp()
    os.chdir(pcs_path)
    commands.init_perun_at(pcs_path, False,
                           {'vcs': {
                               'url': '../',
                               'type': 'git'
                           }})

    # Construct the PCS object
    pcs_obj = pcs.PCS(pcs_path)

    # Initialize git
    vcs.init('git', pcs_path, {})

    # Populate repo with commits
    repo = git.Repo(pcs_path)

    # Create first commit
    file1 = os.path.join(pcs_path, "file1")
    store.touch_file(file1)
    repo.index.add([file1])
    root = repo.index.commit("root")

    # Create second commit
    file2 = os.path.join(pcs_path, "file2")
    store.touch_file(file2)
    repo.index.add([file2])
    current_head = repo.index.commit("second commit")

    # Populate PCS with profiles
    root_profile = Helpers.prepare_profile(pcs_obj, profiles[0], str(root))
    commands.add([root_profile], str(root))
    chead_profile1 = Helpers.prepare_profile(pcs_obj, profiles[1],
                                             str(current_head))
    chead_profile2 = Helpers.prepare_profile(pcs_obj, profiles[2],
                                             str(current_head))
    commands.add([chead_profile1, chead_profile2], str(current_head))

    # Assert that we have five blobs: 2 for commits and 3 for profiles
    pcs_object_dir = os.path.join(pcs_path, ".perun", "objects")
    number_of_perun_objects = sum(
        len(os.listdir(os.path.join(pcs_object_dir, sub)))
        for sub in os.listdir(pcs_object_dir))
    assert number_of_perun_objects == 5

    yield pcs_obj

    # clean up the directory
    shutil.rmtree(pcs_path)
Exemplo n.º 6
0
def add(profile, minor, **kwargs):
    """Links profile to concrete minor version storing its content in the
    ``.perun`` dir and registering the profile in internal minor version index.

    In order to link <profile> to given minor version <hash> the following
    steps are executed:

        1. We check in <profile> that its :preg:`origin` key corresponds to
           <hash>. This serves as a check, that we do not assign profiles to
           different minor versions.

        2. The :preg:`origin` is removed and contents of <profile> are
           compresed using `zlib` compression method.

        3. Binary header for the profile is constructed.

        4. Compressed contents are appended to header, and this blob is stored
           in ``.perun/objects`` directory.

        5. New blob is registered in <hash> minor version's index.

        6. Unless ``--keep-profile`` is set. The original profile is deleted.

    If no `<hash>` is specified, then current ``HEAD`` of the wrapped version
    control system is used instead. Massaging of <hash> is taken care of by
    underlying version control system (e.g. git uses ``git rev-parse``).

    <profile> can either be a ``pending tag`` or a fullpath. ``Pending tags``
    are in form of ``i@p``, where ``i`` stands for an index in the pending
    profile directory (i.e. ``.perun/jobs``) and ``@p`` is literal suffix.
    Run ``perun status`` to see the `tag` anotation of pending profiles.

    Example of adding profiles:

    .. code-block:: bash

        $ perun add mybin-memory-input.txt-2017-03-01-16-11-04.perf

    This command adds the profile collected by `memory` collector during
    profiling ``mybin`` command with ``input.txt`` workload on 1st March at
    16:11 to the current ``HEAD``.

    An error is raised if the command is executed outside of range of any
    perun, if <profile> points to incorrect profile (i.e. not w.r.t.
    :ref:`profile-spec`) or <hash> does not point to valid minor version ref.

    See :doc:`internals` for information how perun handles profiles internally.
    """
    try:
        commands.add(profile, minor, **kwargs)
    except (NotPerunRepositoryException,
            IncorrectProfileFormatException) as exception:
        perun_log.error(str(exception))
Exemplo n.º 7
0
def test_add_on_no_vcs(helpers, pcs_without_vcs, valid_profile_pool):
    """Test calling 'perun add' without having a wrapped vcs

    Expecting and error, as this will call a wrapper over custom "repo" called pvcs, which
    is not supported, but is simply a sane default.
    """
    before_count = helpers.count_contents_on_path(pcs_without_vcs.path)
    assert pcs_without_vcs.vcs_type == 'pvcs'
    with pytest.raises(UnsupportedModuleException):
        commands.add([valid_profile_pool[0]], None, keep_profile=True)

    # Assert that nothing was added (rather weak, but should be enough)
    after_count = helpers.count_contents_on_path(pcs_without_vcs.path)
    assert before_count == after_count
Exemplo n.º 8
0
def test_add_wrong_minor(helpers, pcs_full, valid_profile_pool):
    """Test calling 'perun add profile hash' with hash not occuring in wrapped VCS

    Expecting raising an exception, that the specified minor version is wrong.
    """
    git_repo = git.Repo(os.path.split(pcs_full.path)[0])
    commits = [binascii.hexlify(c.binsha).decode('utf-8') for c in git_repo.iter_commits()]
    wrong_commit = commits[0][:20] + commits[1][20:]
    assert len(wrong_commit) == 40
    assert wrong_commit != commits[0] and wrong_commit != commits[1]
    before_count = helpers.count_contents_on_path(pcs_full.path)

    with pytest.raises(VersionControlSystemException):
        commands.add([valid_profile_pool[0]], wrong_commit, keep_profile=True)

    # Assert that nothing was added (rather weak, but should be enough)
    after_count = helpers.count_contents_on_path(pcs_full.path)
    assert before_count == after_count
Exemplo n.º 9
0
def test_add_existing(helpers, pcs_full, valid_profile_pool, capsys):
    """Test calling 'perun add profile hash', when the profile is already assigned to current

    Expecting probably to warn the user, that the profile is already assigned and don't change
    anything or add new redundant entry for that.

    Fixme: Extend with more checks
    """
    git_repo = git.Repo(os.path.split(pcs_full.get_path())[0])
    head = str(git_repo.head.commit)
    before_count = helpers.count_contents_on_path(pcs_full.get_path())
    obj_path = pcs_full.get_path()

    for valid_profile in valid_profile_pool:
        valid_profile = helpers.prepare_profile(pcs_full.get_job_directory(),
                                                valid_profile, head)
        # Check that the profile was NOT in the index before
        before_entries_count = assert_before_add(helpers, obj_path, head,
                                                 valid_profile)

        commands.add([valid_profile], None, keep_profile=True)

        # Assert that the profile was successfully added to the index
        middle_entries_count = assert_after_valid_add(helpers, obj_path, head,
                                                      valid_profile)
        assert before_entries_count == (middle_entries_count - 1)

        commands.add([valid_profile], None, keep_profile=True)

        # Assert that nothing was added to the index
        after_entries_count = assert_after_valid_add(helpers, obj_path, head,
                                                     valid_profile)
        assert middle_entries_count == after_entries_count

        # Check that some kind of message was written to user
        out, _ = capsys.readouterr()
        assert 'already registered in' in out

    # Assert that just len-1 blobs was added, as the second profile has the same structure as
    #   one of the profiles already in the tracking
    after_count = helpers.count_contents_on_path(pcs_full.get_path())
    assert before_count[0] == (after_count[0] - (len(valid_profile_pool) - 1) -
                               2)
Exemplo n.º 10
0
def register_profile_of_minor_version(pcs, minor_version, profile_path, profile_id):
    """Function for registering performance profile of a minor version
    :param PCS pcs: object with performance control system wrapper
    :param str minor_version_sha: minor version SHA
    :param str profile_path: path to the performance profile
    :param str profile_id: name of the performance profile
    :return: new profile path on success, otherwise 404 NOT FOUND
    """
    try: 
        commands.add([profile_path], minor_version, keep_profile=False)
        profiles = commands.get_minor_version_profiles(pcs, minor_version);
        for perf_profile in profiles:
            if (perf_profile.source == profile_id):
                return jsonify({'path' : perf_profile.realpath})

        return create_response('No such performance profile', 404)
    
    except Exception as e:
        eprint(e)
        return create_response(e, 404)
Exemplo n.º 11
0
def store_generated_profile(prof, job):
    """Stores the generated profile in the pending jobs directory.

    :param dict prof: profile that we are storing in the repository
    :param Job job: job with additional information about generated profiles
    """
    full_profile = profile.finalize_profile_for_job(prof, job)
    full_profile_name = profile.generate_profile_name(full_profile)
    profile_directory = pcs.get_job_directory()
    full_profile_path = os.path.join(profile_directory, full_profile_name)
    profile.store_profile_at(full_profile, full_profile_path)
    log.info("stored profile at: {}".format(
        os.path.relpath(full_profile_path)))
    if dutils.strtobool(
            str(
                config.lookup_key_recursively("profiles.register_after_run",
                                              "false"))):
        # We either store the profile according to the origin, or we use the current head
        dst = prof.get('origin', vcs.get_minor_head())
        commands.add([full_profile_path], dst, keep_profile=False)
Exemplo n.º 12
0
def test_add_on_empty_repo(helpers, pcs_with_empty_git, valid_profile_pool, capsys):
    """Test calling 'perun add' on empty repository

    Expecting an error and system exist as there is no commit, so nothing can be add.
    """
    assert os.getcwd() == os.path.split(pcs_with_empty_git.path)[0]
    before_count = helpers.count_contents_on_path(pcs_with_empty_git.path)

    # Assert that the program ends
    with pytest.raises(SystemExit):
        commands.add([valid_profile_pool[0]], None, keep_profile=True)

    # Assert that nothing was added (rather weak, but should be enough)
    after_count = helpers.count_contents_on_path(pcs_with_empty_git.path)
    assert before_count == after_count

    # Assert that the error message is OK
    _, err = capsys.readouterr()
    expected = "fatal: could not obtain head minor version: " \
               "Reference at 'refs/heads/master' does not exist"
    assert err.strip() == termcolor.colored(expected, 'red')
Exemplo n.º 13
0
def pcs_with_degradations():
    """
    """
    pool_path = os.path.join(os.path.split(__file__)[0], 'degradation_profiles')
    profiles = [
        os.path.join(pool_path, 'linear_base.perf'),
        os.path.join(pool_path, 'linear_base_degradated.perf'),
        os.path.join(pool_path, 'quad_base.perf')
    ]
    # Change working dir into the temporary directory
    pcs_path = tempfile.mkdtemp()
    os.chdir(pcs_path)
    commands.init_perun_at(pcs_path, False, {'vcs': {'url': '../', 'type': 'git'}})

    # Initialize git
    vcs.init({})

    # Populate repo with commits
    repo = git.Repo(pcs_path)

    # Create first commit
    file1 = os.path.join(pcs_path, "file1")
    store.touch_file(file1)
    repo.index.add([file1])
    root = repo.index.commit("root")

    # Create second commit
    repo.git.checkout('-b', 'develop')
    file2 = os.path.join(pcs_path, "file2")
    store.touch_file(file2)
    repo.index.add([file2])
    middle_head = repo.index.commit("second commit")

    # Create third commit
    repo.git.checkout('master')
    file3 = os.path.join(pcs_path, "file3")
    store.touch_file(file3)
    repo.index.add([file3])
    repo.index.commit("parallel commit")
    repo.git.merge('--no-ff', 'develop')
    current_head = str(repo.head.commit)

    # Populate PCS with profiles
    jobs_dir = pcs.get_job_directory()
    root_profile = Helpers.prepare_profile(jobs_dir, profiles[0], str(root))
    commands.add([root_profile], str(root))
    middle_profile = Helpers.prepare_profile(jobs_dir, profiles[1], str(middle_head))
    commands.add([middle_profile], str(middle_head))
    head_profile = Helpers.prepare_profile(jobs_dir, profiles[2], str(current_head))
    commands.add([head_profile], str(current_head))

    yield pcs

    # clean up the directory
    shutil.rmtree(pcs_path)