<commit_before>import os
import re

import pytest
from cookiecutter.exceptions import FailedHookException
import sh
import yaml
from binaryornot.check import is_binary

PATTERN = r"{{(\s?cookiecutter)[.](.*?)}}"
RE_OBJ = re.compile(PATTERN)

@pytest.fixture
def context():
    return {
        "project_name": "My Test Project",
        "project_slug": "my_test_project",
        "author_name": "Test Author",
        "email": "test@example.com",
        "description": "A short description of the project.",
        "domain_name": "example.com",
        "version": "0.1.0",
        "timezone": "UTC",
    }

SUPPORTED_COMBINATIONS = [
    {"open_source_license": "MIT"},
    {"open_source_license": "BSD"},
    {"open_source_license": "GPLv3"},
    {"open_source_license": "Apache Software License 2.0"},
    {"open_source_license": "Not open source"},
    {"windows": "y"},
    {"windows": "n"},
    {"use_pycharm": "y"},
    {"use_pycharm": "n"},
    {"use_docker": "y"},
    {"use_docker": "n"},
    {"postgresql_version": "11.3"},
    {"postgresql_version": "10.8"},
    {"postgresql_version": "9.6"},
    {"postgresql_version": "9.5"},
    {"postgresql_version": "9.4"},
    {"cloud_provider": "AWS", "use_whitenoise": "y"},
    {"cloud_provider": "AWS", "use_whitenoise": "n"},
    {"cloud_provider": "GCP", "use_whitenoise": "y"},
    {"cloud_provider": "GCP", "use_whitenoise": "n"},
    {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Mailgun"},
    {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Mailjet"},
    {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Mandrill"},
    {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Postmark"},
    {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Sendgrid"},
    {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "SendinBlue"},
    {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "SparkPost"},
    {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Other SMTP"},
    # Note: cloud_provider=None AND use_whitenoise=n is not supported
    {"cloud_provider": "AWS", "mail_service": "Mailgun"},
    {"cloud_provider": "AWS", "mail_service": "Amazon SES"},
    {"cloud_provider": "AWS", "mail_service": "Mailjet"},
    {"cloud_provider": "AWS", "mail_service": "Mandrill"},
    {"cloud_provider": "AWS", "mail_service": "Postmark"},
    {"cloud_provider": "AWS", "mail_service": "Sendgrid"},
    {"cloud_provider": "AWS", "mail_service": "SendinBlue"},
    {"cloud_provider": "AWS", "mail_service": "SparkPost"},
    {"cloud_provider": "AWS", "mail_service": "Other SMTP"},
    {"cloud_provider": "GCP", "mail_service": "Mailgun"},
    {"cloud_provider": "GCP", "mail_service": "Mailjet"},
    {"cloud_provider": "GCP", "mail_service": "Mandrill"},
    {"cloud_provider": "GCP", "mail_service": "Postmark"},
    {"cloud_provider": "GCP", "mail_service": "Sendgrid"},
    {"cloud_provider": "GCP", "mail_service": "SendinBlue"},
    {"cloud_provider": "GCP", "mail_service": "SparkPost"},
    {"cloud_provider": "GCP", "mail_service": "Other SMTP"},
    # Note: cloud_providers GCP and None with mail_service Amazon SES is not supported
    {"use_async", "y"},
    {"use_async", "n"},
    {"use_drf": "y"},
    {"use_drf": "n"},
    {"js_task_runner": "None"},
    {"js_task_runner": "Gulp"},
    {"custom_bootstrap_compilation": "y"},
    {"custom_bootstrap_compilation": "n"},
    {"use_compressor": "y"},
    {"use_compressor": "n"},
    {"use_celery": "y"},
    {"use_celery": "n"},
    {"use_mailhog": "y"},
    {"use_mailhog": "n"},
    {"use_sentry": "y"},
    {"use_sentry": "n"},
    {"use_whitenoise": "y"},
    {"use_whitenoise": "n"},
    {"use_heroku": "y"},
    {"use_heroku": "n"},
    {"ci_tool": "None"},
    {"ci_tool": "Travis"},
    {"ci_tool": "Gitlab"},
    {"keep_local_envs_in_vcs": "y"},
    {"keep_local_envs_in_vcs": "n"},
    {"debug": "y"},
    {"debug": "n"},
]

UNSUPPORTED_COMBINATIONS = [
    {"cloud_provider": "None", "use_whitenoise": "n"},
    {"cloud_provider": "GCP", "mail_service": "Amazon SES"},
    {"cloud_provider": "None", "mail_service": "Amazon SES"},
]

def _fixture_id(ctx):
    """Helper to get a user friendly test name from the parametrized context."""
    return "-".join(f"{key}:{value}" for key, value in ctx.items())

def build_files_list(root_dir):
    """Build a list containing absolute paths to the generated files."""
    return [
        os.path.join(dirpath, file_path)
        for dirpath, subdirs, files in os.walk(root_dir)
        for file_path in files
    ]

def check_paths(paths):
    """Method to check all paths have correct substitutions."""
    # Assert that no match is found in any of the files
    for path in paths:
        if is_binary(path):
            continue

        for line in open(path, "r"):
            match = RE_OBJ.search(line)
            msg = "cookiecutter variable not replaced in {}"
            assert match is None, msg.format(path)

@pytest.mark.parametrize("context_override", SUPPORTED_COMBINATIONS, ids=_fixture_id)
def test_project_generation(cookies, context, context_override):
    """Test that project is generated and fully rendered."""
    result = cookies.bake(extra_context={**context, **context_override})
    assert result.exit_code == 0
    assert result.exception is None
    assert result.project.basename == context["project_slug"]
    assert result.project.isdir()

    paths = build_files_list(str(result.project))
    assert paths
    check_paths(paths)

@pytest.mark.parametrize("context_override", SUPPORTED_COMBINATIONS, ids=_fixture_id)
def test_flake8_passes(cookies, context_override):
    """Generated project should pass flake8."""
    result = cookies.bake(extra_context=context_override)

    try:
        sh.flake8(str(result.project))
    except sh.ErrorReturnCode as e:
        pytest.fail(e.stdout.decode())

@pytest.mark.parametrize("context_override", SUPPORTED_COMBINATIONS, ids=_fixture_id)
def test_black_passes(cookies, context_override):
    """Generated project should pass black."""
    result = cookies.bake(extra_context=context_override)

    try:
        sh.black("--check", "--diff", "--exclude", "migrations", f"{result.project}/")
    except sh.ErrorReturnCode as e:
        pytest.fail(e.stdout.decode())

def test_travis_invokes_pytest(cookies, context):
    context.update({"ci_tool": "Travis"})
    result = cookies.bake(extra_context=context)

    assert result.exit_code == 0
    assert result.exception is None
    assert result.project.basename == context["project_slug"]
    assert result.project.isdir()

    with open(f"{result.project}/.travis.yml", "r") as travis_yml:
        try:
            assert yaml.load(travis_yml, Loader=yaml.FullLoader)["script"] == ["pytest"]
        except yaml.YAMLError as e:
            pytest.fail(e)

def test_gitlab_invokes_flake8_and_pytest(cookies, context):
    context.update({"ci_tool": "Gitlab"})
    result = cookies.bake(extra_context=context)

    assert result.exit_code == 0
    assert result.exception is None
    assert result.project.basename == context["project_slug"]
    assert result.project.isdir()

    with open(f"{result.project}/.gitlab-ci.yml", "r") as gitlab_yml:
        try:
            gitlab_config = yaml.load(gitlab_yml, Loader=yaml.FullLoader)
            assert gitlab_config["flake8"]["script"] == ["flake8"]
            assert gitlab_config["pytest"]["script"] == ["pytest"]
        except yaml.YAMLError as e:
            pytest.fail(e)

@pytest.mark.parametrize("slug", ["project slug", "Project_Slug"])
def test_invalid_slug(cookies, context, slug):
    """Invalid slug should failed pre-generation hook."""
    context.update({"project_slug": slug})

    result = cookies.bake(extra_context=context)

    assert result.exit_code != 0
    assert isinstance(result.exception, FailedHookException)

@pytest.mark.parametrize("invalid_context", UNSUPPORTED_COMBINATIONS)
def test_error_if_incompatible(cookies, context, invalid_context):
    """It should not generate project an incompatible combination is selected."""
    context.update(invalid_context)
    result = cookies.bake(extra_context=context)

    assert result.exit_code != 0
    assert isinstance(result.exception, FailedHookException)
<commit_msg>Fixed test_cookiecutter_generation.py for use_async from set to dict<commit_after>import os
import re

import pytest
from cookiecutter.exceptions import FailedHookException
import sh
import yaml
from binaryornot.check import is_binary

PATTERN = r"{{(\s?cookiecutter)[.](.*?)}}"
RE_OBJ = re.compile(PATTERN)

@pytest.fixture
def context():
    return {
        "project_name": "My Test Project",
        "project_slug": "my_test_project",
        "author_name": "Test Author",
        "email": "test@example.com",
        "description": "A short description of the project.",
        "domain_name": "example.com",
        "version": "0.1.0",
        "timezone": "UTC",
    }

SUPPORTED_COMBINATIONS = [
    {"open_source_license": "MIT"},
    {"open_source_license": "BSD"},
    {"open_source_license": "GPLv3"},
    {"open_source_license": "Apache Software License 2.0"},
    {"open_source_license": "Not open source"},
    {"windows": "y"},
    {"windows": "n"},
    {"use_pycharm": "y"},
    {"use_pycharm": "n"},
    {"use_docker": "y"},
    {"use_docker": "n"},
    {"postgresql_version": "11.3"},
    {"postgresql_version": "10.8"},
    {"postgresql_version": "9.6"},
    {"postgresql_version": "9.5"},
    {"postgresql_version": "9.4"},
    {"cloud_provider": "AWS", "use_whitenoise": "y"},
    {"cloud_provider": "AWS", "use_whitenoise": "n"},
    {"cloud_provider": "GCP", "use_whitenoise": "y"},
    {"cloud_provider": "GCP", "use_whitenoise": "n"},
    {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Mailgun"},
    {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Mailjet"},
    {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Mandrill"},
    {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Postmark"},
    {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Sendgrid"},
    {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "SendinBlue"},
    {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "SparkPost"},
    {"cloud_provider": "None", "use_whitenoise": "y", "mail_service": "Other SMTP"},
    # Note: cloud_provider=None AND use_whitenoise=n is not supported
    {"cloud_provider": "AWS", "mail_service": "Mailgun"},
    {"cloud_provider": "AWS", "mail_service": "Amazon SES"},
    {"cloud_provider": "AWS", "mail_service": "Mailjet"},
    {"cloud_provider": "AWS", "mail_service": "Mandrill"},
    {"cloud_provider": "AWS", "mail_service": "Postmark"},
    {"cloud_provider": "AWS", "mail_service": "Sendgrid"},
    {"cloud_provider": "AWS", "mail_service": "SendinBlue"},
    {"cloud_provider": "AWS", "mail_service": "SparkPost"},
    {"cloud_provider": "AWS", "mail_service": "Other SMTP"},
    {"cloud_provider": "GCP", "mail_service": "Mailgun"},
    {"cloud_provider": "GCP", "mail_service": "Mailjet"},
    {"cloud_provider": "GCP", "mail_service": "Mandrill"},
    {"cloud_provider": "GCP", "mail_service": "Postmark"},
    {"cloud_provider": "GCP", "mail_service": "Sendgrid"},
    {"cloud_provider": "GCP", "mail_service": "SendinBlue"},
    {"cloud_provider": "GCP", "mail_service": "SparkPost"},
    {"cloud_provider": "GCP", "mail_service": "Other SMTP"},
    # Note: cloud_providers GCP and None with mail_service Amazon SES is not supported
    {"use_async": "y"},
    {"use_async": "n"},
    {"use_drf": "y"},
    {"use_drf": "n"},
    {"js_task_runner": "None"},
    {"js_task_runner": "Gulp"},
    {"custom_bootstrap_compilation": "y"},
    {"custom_bootstrap_compilation": "n"},
    {"use_compressor": "y"},
    {"use_compressor": "n"},
    {"use_celery": "y"},
    {"use_celery": "n"},
    {"use_mailhog": "y"},
    {"use_mailhog": "n"},
    {"use_sentry": "y"},
    {"use_sentry": "n"},
    {"use_whitenoise": "y"},
    {"use_whitenoise": "n"},
    {"use_heroku": "y"},
    {"use_heroku": "n"},
    {"ci_tool": "None"},
    {"ci_tool": "Travis"},
    {"ci_tool": "Gitlab"},
    {"keep_local_envs_in_vcs": "y"},
    {"keep_local_envs_in_vcs": "n"},
    {"debug": "y"},
    {"debug": "n"},
]

UNSUPPORTED_COMBINATIONS = [
    {"cloud_provider": "None", "use_whitenoise": "n"},
    {"cloud_provider": "GCP", "mail_service": "Amazon SES"},
    {"cloud_provider": "None", "mail_service": "Amazon SES"},
]

def _fixture_id(ctx):
    """Helper to get a user friendly test name from the parametrized context."""
    return "-".join(f"{key}:{value}" for key, value in ctx.items())

def build_files_list(root_dir):
    """Build a list containing absolute paths to the generated files."""
    return [
        os.path.join(dirpath, file_path)
        for dirpath, subdirs, files in os.walk(root_dir)
        for file_path in files
    ]

def check_paths(paths):
    """Method to check all paths have correct substitutions."""
    # Assert that no match is found in any of the files
    for path in paths:
        if is_binary(path):
            continue

        for line in open(path, "r"):
            match = RE_OBJ.search(line)
            msg = "cookiecutter variable not replaced in {}"
            assert match is None, msg.format(path)

@pytest.mark.parametrize("context_override", SUPPORTED_COMBINATIONS, ids=_fixture_id)
def test_project_generation(cookies, context, context_override):
    """Test that project is generated and fully rendered."""
    result = cookies.bake(extra_context={**context, **context_override})
    assert result.exit_code == 0
    assert result.exception is None
    assert result.project.basename == context["project_slug"]
    assert result.project.isdir()

    paths = build_files_list(str(result.project))
    assert paths
    check_paths(paths)

@pytest.mark.parametrize("context_override", SUPPORTED_COMBINATIONS, ids=_fixture_id)
def test_flake8_passes(cookies, context_override):
    """Generated project should pass flake8."""
    result = cookies.bake(extra_context=context_override)

    try:
        sh.flake8(str(result.project))
    except sh.ErrorReturnCode as e:
        pytest.fail(e.stdout.decode())

@pytest.mark.parametrize("context_override", SUPPORTED_COMBINATIONS, ids=_fixture_id)
def test_black_passes(cookies, context_override):
    """Generated project should pass black."""
    result = cookies.bake(extra_context=context_override)

    try:
        sh.black("--check", "--diff", "--exclude", "migrations", f"{result.project}/")
    except sh.ErrorReturnCode as e:
        pytest.fail(e.stdout.decode())

def test_travis_invokes_pytest(cookies, context):
    context.update({"ci_tool": "Travis"})
    result = cookies.bake(extra_context=context)

    assert result.exit_code == 0
    assert result.exception is None
    assert result.project.basename == context["project_slug"]
    assert result.project.isdir()

    with open(f"{result.project}/.travis.yml", "r") as travis_yml:
        try:
            assert yaml.load(travis_yml, Loader=yaml.FullLoader)["script"] == ["pytest"]
        except yaml.YAMLError as e:
            pytest.fail(e)

def test_gitlab_invokes_flake8_and_pytest(cookies, context):
    context.update({"ci_tool": "Gitlab"})
    result = cookies.bake(extra_context=context)

    assert result.exit_code == 0
    assert result.exception is None
    assert result.project.basename == context["project_slug"]
    assert result.project.isdir()

    with open(f"{result.project}/.gitlab-ci.yml", "r") as gitlab_yml:
        try:
            gitlab_config = yaml.load(gitlab_yml, Loader=yaml.FullLoader)
            assert gitlab_config["flake8"]["script"] == ["flake8"]
            assert gitlab_config["pytest"]["script"] == ["pytest"]
        except yaml.YAMLError as e:
            pytest.fail(e)

@pytest.mark.parametrize("slug", ["project slug", "Project_Slug"])
def test_invalid_slug(cookies, context, slug):
    """Invalid slug should failed pre-generation hook."""
    context.update({"project_slug": slug})

    result = cookies.bake(extra_context=context)

    assert result.exit_code != 0
    assert isinstance(result.exception, FailedHookException)

@pytest.mark.parametrize("invalid_context", UNSUPPORTED_COMBINATIONS)
def test_error_if_incompatible(cookies, context, invalid_context):
    """It should not generate project an incompatible combination is selected."""
    context.update(invalid_context)
    result = cookies.bake(extra_context=context)

    assert result.exit_code != 0
    assert isinstance(result.exception, FailedHookException)
<|endoftext|>


<commit_before>from __future__ import print_function

import inspect
import logging
from functools import partial

import attr
import numpy as np
import scipy.optimize
from pytest import approx

from fastimgproto.fixtures.image import add_gaussian2d_to_image
from fastimgproto.fixtures.sourcefits import (
    check_single_source_extraction_successful,
    generate_random_source_params,
)
from fastimgproto.sourcefind.fit import (
    Gaussian2dParams,
    gaussian2d,
    gaussian2d_jac,
)
from fastimgproto.sourcefind.image import SourceFindImage

logger = logging.getLogger(__name__)

def test_gauss2d_func_and_jacobian():
    assert (inspect.getargspec(gaussian2d).args ==
            inspect.getargspec(gaussian2d_jac).args)

    profile = Gaussian2dParams(x_centre=4,
                               y_centre=9,
                               amplitude=10.,
                               semimajor=1.5,
                               semiminor=1.2,
                               theta=np.pi / 4.
                               )
    # Generate some random positions to test
    rstate = np.random.RandomState(seed=42)
    n_samples = 10

    pars = attr.astuple(profile)
    n_tests_run = 0
    for x in rstate.uniform(profile.x_centre - profile.semimajor * 5.,
                            profile.x_centre + profile.semimajor * 5.,
                            size=n_samples
                            ):
        for y in rstate.uniform(profile.y_centre - profile.semimajor * 5.,
                                profile.y_centre + profile.semimajor * 5.,
                                size=n_samples
                                ):
            # Need to partially bind the functions for each x/y location
            def located_g2d(x_centre, y_centre, amplitude, x_stddev, y_stddev,
                            theta):
                return gaussian2d(x, y, x_centre, y_centre, amplitude,
                                  x_stddev, y_stddev,
                                  theta)

            def located_g2d_jac(x_centre, y_centre, amplitude, x_stddev,
                                y_stddev,
                                theta):
                return gaussian2d_jac(x, y, x_centre, y_centre, amplitude,
                                      x_stddev, y_stddev,
                                      theta)

            def wrapped_gaussian2d(pars):
                assert len(pars) == 6
                return located_g2d(*pars)

            def wrapped_gaussian2d_jac(pars):
                assert len(pars) == 6
                return located_g2d_jac(*pars)

            n_tests_run += 1
            logger.debug("Gradient check {} of {}".format(
                n_tests_run, n_samples ** 2))
            logger.debug("Checking gradient at x/y position {} {}".format(x, y))

            eps = np.sqrt(np.finfo(float).eps) # default for check_grad
            # eps = 1e-12

            numerical = scipy.optimize.approx_fprime(pars, wrapped_gaussian2d,
                                                     epsilon=eps, )
            analytic = wrapped_gaussian2d_jac(pars)
            check_grad_result = scipy.optimize.check_grad(
                wrapped_gaussian2d,
                wrapped_gaussian2d_jac,
                x0=pars,
                epsilon=eps,
            )
            logger.debug("Analytic {}".format(analytic))
            logger.debug("Numerical {}".format(numerical))

            logger.debug("Diffs: manual {}, check grad {}".format(
                np.abs(analytic - numerical),
                check_grad_result))
            logger.debug("")

            np.testing.assert_allclose(analytic,numerical,
                                       atol=1e-7)
            assert check_grad_result == approx(0., abs=2e-6)

    def test_basic_source_detection_and_fitting():
        ydim = 64
        xdim = 32
        image_shape = (ydim, xdim)
        seed = 123456

        base_x = 18
        base_y = 34
        n_sources = 10
        positive_sources = generate_random_source_params(n_sources=n_sources,
                                                         base_x=base_x,
                                                         base_y=base_y,
                                                         amplitude_range=(
                                                             4.5, 42.),
                                                         semiminor_range=(
                                                             0.4, 2.),
                                                         axis_ratio_range=(
                                                             1., 5.),
                                                         seed=123456,
                                                         )
        n_islands = 0
        fits = []
        for src in positive_sources:
            img = np.zeros(image_shape)
            add_gaussian2d_to_image(src, img)
            detection_thresh = 4.
            sfimg = SourceFindImage(img, detection_n_sigma=detection_thresh,
                                    analysis_n_sigma=3.,
                                    rms_est=1.,
                                    find_negative_sources=True)

            check_single_source_extraction_successful(src, sfimg)
            if sfimg.islands:
                n_islands += 1
                assert len(sfimg.islands) == 1
                lsq_fit = sfimg.fit_gaussian_2d(sfimg.islands[0], verbose=1)
                fits.append(lsq_fit)
            else:
                fits.append(None)

        n_completed_fits = sum(
            1 for f in fits if f)  # Count where f is not False
        logger.debug(
            "{} of {} island-fits completed".format(n_completed_fits,
                                                    n_islands))

        success = np.zeros_like(positive_sources, dtype=int)
        for idx, lsq_fit in enumerate(fits):
            if lsq_fit is None:
                success[idx] = 1  # Trivial no-island case. Count as OK.
            elif (positive_sources[idx].comparable_params ==
                      approx(lsq_fit.comparable_params, rel=1e-2)):
                success[idx] = 1

        n_successful = success.sum()
        logger.debug("{} of {} sources fitted accurately".format(
            n_successful, len(positive_sources)
        ))
        # assert n_successful == len(positive_sources )

        bad_idx = np.where(success == 0)
        bad_truth = np.array([attr.astuple(s) for s in positive_sources])[
            bad_idx]
        bad_fits = np.array([attr.astuple(s) for s in fits])[bad_idx]
<commit_msg>Comment debug logging from check_grad test<commit_after>from __future__ import print_function

import inspect
import logging
from functools import partial

import attr
import numpy as np
import scipy.optimize
from pytest import approx

from fastimgproto.fixtures.image import add_gaussian2d_to_image
from fastimgproto.fixtures.sourcefits import (
    check_single_source_extraction_successful,
    generate_random_source_params,
)
from fastimgproto.sourcefind.fit import (
    Gaussian2dParams,
    gaussian2d,
    gaussian2d_jac,
)
from fastimgproto.sourcefind.image import SourceFindImage

logger = logging.getLogger(__name__)

def test_gauss2d_func_and_jacobian():
    assert (inspect.getargspec(gaussian2d).args ==
            inspect.getargspec(gaussian2d_jac).args)

    profile = Gaussian2dParams(x_centre=4,
                               y_centre=9,
                               amplitude=10.,
                               semimajor=1.5,
                               semiminor=1.2,
                               theta=np.pi / 4.
                               )
    # Generate some random positions to test
    rstate = np.random.RandomState(seed=42)
    n_samples = 10

    pars = attr.astuple(profile)
    n_tests_run = 0
    for x in rstate.uniform(profile.x_centre - profile.semimajor * 5.,
                            profile.x_centre + profile.semimajor * 5.,
                            size=n_samples
                            ):
        for y in rstate.uniform(profile.y_centre - profile.semimajor * 5.,
                                profile.y_centre + profile.semimajor * 5.,
                                size=n_samples
                                ):
            # Need to partially bind the functions for each x/y location
            def located_g2d(x_centre, y_centre, amplitude, x_stddev, y_stddev,
                            theta):
                return gaussian2d(x, y, x_centre, y_centre, amplitude,
                                  x_stddev, y_stddev,
                                  theta)

            def located_g2d_jac(x_centre, y_centre, amplitude, x_stddev,
                                y_stddev,
                                theta):
                return gaussian2d_jac(x, y, x_centre, y_centre, amplitude,
                                      x_stddev, y_stddev,
                                      theta)

            def wrapped_gaussian2d(pars):
                assert len(pars) == 6
                return located_g2d(*pars)

            def wrapped_gaussian2d_jac(pars):
                assert len(pars) == 6
                return located_g2d_jac(*pars)

            n_tests_run += 1
            logger.debug("Gradient check {} of {}".format(
                n_tests_run, n_samples ** 2))
            logger.debug("Checking gradient at x/y position {} {}".format(x, y))

            eps = np.sqrt(np.finfo(float).eps) # default for check_grad
            # eps = 1e-12

            numerical = scipy.optimize.approx_fprime(pars, wrapped_gaussian2d,
                                                     epsilon=eps, )
            analytic = wrapped_gaussian2d_jac(pars)
            check_grad_result = scipy.optimize.check_grad(
                wrapped_gaussian2d,
                wrapped_gaussian2d_jac,
                x0=pars,
                epsilon=eps,
            )
            # logger.debug("Analytic {}".format(analytic))
            # logger.debug("Numerical {}".format(numerical))
            #
            # logger.debug("Diffs: manual {}, check grad {}".format(
            #     np.abs(analytic - numerical),
            #     check_grad_result))
            # logger.debug("")

            np.testing.assert_allclose(analytic,numerical,
                                       atol=1e-7)
            assert check_grad_result == approx(0., abs=2e-6)

    def test_basic_source_detection_and_fitting():
        ydim = 64
        xdim = 32
        image_shape = (ydim, xdim)
        seed = 123456

        base_x = 18
        base_y = 34
        n_sources = 10
        positive_sources = generate_random_source_params(n_sources=n_sources,
                                                         base_x=base_x,
                                                         base_y=base_y,
                                                         amplitude_range=(
                                                             4.5, 42.),
                                                         semiminor_range=(
                                                             0.4, 2.),
                                                         axis_ratio_range=(
                                                             1., 5.),
                                                         seed=123456,
                                                         )
        n_islands = 0
        fits = []
        for src in positive_sources:
            img = np.zeros(image_shape)
            add_gaussian2d_to_image(src, img)
            detection_thresh = 4.
            sfimg = SourceFindImage(img, detection_n_sigma=detection_thresh,
                                    analysis_n_sigma=3.,
                                    rms_est=1.,
                                    find_negative_sources=True)

            check_single_source_extraction_successful(src, sfimg)
            if sfimg.islands:
                n_islands += 1
                assert len(sfimg.islands) == 1
                lsq_fit = sfimg.fit_gaussian_2d(sfimg.islands[0], verbose=1)
                fits.append(lsq_fit)
            else:
                fits.append(None)

        n_completed_fits = sum(
            1 for f in fits if f)  # Count where f is not False
        logger.debug(
            "{} of {} island-fits completed".format(n_completed_fits,
                                                    n_islands))

        success = np.zeros_like(positive_sources, dtype=int)
        for idx, lsq_fit in enumerate(fits):
            if lsq_fit is None:
                success[idx] = 1  # Trivial no-island case. Count as OK.
            elif (positive_sources[idx].comparable_params ==
                      approx(lsq_fit.comparable_params, rel=1e-2)):
                success[idx] = 1

        n_successful = success.sum()
        logger.debug("{} of {} sources fitted accurately".format(
            n_successful, len(positive_sources)
        ))
        # assert n_successful == len(positive_sources )

        bad_idx = np.where(success == 0)
        bad_truth = np.array([attr.astuple(s) for s in positive_sources])[
            bad_idx]
        bad_fits = np.array([attr.astuple(s) for s in fits])[bad_idx]
<|endoftext|>


<commit_before>"""
Simple sanity test for VM/template systems

TODO: Possibly mock this out, remove reliance on 'cfme', etc.

If running within a cfme venv, disable the cfme plugins like so:
   $ pytest test_vm_and_template_systems.py -p no:cfme -s
"""

import datetime
import logging

import pytest
import fauxfactory
from wait_for import wait_for

import wrapanapi
from wrapanapi import VmState
from wrapanapi.entities import StackMixin
from wrapanapi.systems.ec2 import EC2Image, EC2Instance, StackStates
from wrapanapi.exceptions import MultipleItemsError

log = logging.getLogger('wrapanapi.tests.test_vm_and_template_systems')

logging.basicConfig(level=logging.INFO)

PROVIDER_KEYS_LIST = ['ec2west']
#    'rhos11', 'vsphere65-nested', 'scvmm', 'azure', 'gce_central', 'ec2west', 'rhv41'
#]

@pytest.fixture(params=PROVIDER_KEYS_LIST)
def provider_crud(request):
    providers = pytest.importorskip('cfme.utils.providers')
    log.info("Using provider key: %s", request.param)
    return providers.get_crud(request.param)

@pytest.fixture
def test_template(provider_crud):
    deploy_args = {}
    try:
        template_name = provider_crud.data['templates']['small_template']['name']
        deploy_args.update({'template': template_name})
    except KeyError:
        raise KeyError('small_template not defined for Provider {} in cfme_data.yaml'
                       .format(provider_crud.data['name']))
    log.info(
        "Using template %s on provider %s",
        deploy_args['template'], provider_crud.data['name']
    )

    deploy_args.update(vm_name='TBD')
    deploy_args.update(provider_crud.deployment_helper(deploy_args))
    log.debug("Deploy args: %s", deploy_args)

    if isinstance(provider_crud.mgmt, wrapanapi.systems.AzureSystem):
        template = provider_crud.mgmt.get_template(
            template_name, container=deploy_args['template_container'])
    else:
        template = provider_crud.mgmt.get_template(template_name)

    return template

@pytest.yield_fixture
def test_vm(provider_crud, test_template):
    deploy_args = {}
    try:
        template_name = provider_crud.data['templates']['small_template']['name']
        deploy_args.update({'template': template_name})
    except KeyError:
        raise KeyError('small_template not defined for Provider {} in cfme_data.yaml'
                       .format(provider_crud.data['name']))

    vm_name = 'test-{}'.format(fauxfactory.gen_alphanumeric(6)).lower()
    log.info("Deploying VM %s", vm_name)

    deploy_args.update(vm_name=vm_name)
    deploy_args.update(provider_crud.deployment_helper(deploy_args))
    log.debug("Deploy args: %s", deploy_args)

    vm = test_template.deploy(timeout=900, **deploy_args)

    yield vm

    try:
        vm.cleanup()
    except Exception:
        log.exception("Failed to cleanup vm")

def test_sanity(provider_crud, test_template, test_vm):

    template = test_template
    vm = test_vm
    mgmt = provider_crud.mgmt

    if isinstance(mgmt, StackMixin):
        stacks = mgmt.list_stacks(StackStates.ALL)
        assert [repr(stack) for stack in stacks]
        assert str(stacks[0])
        stack = stacks[0]
        assert stack in mgmt.find_stacks(name=stack.name)
        assert mgmt.get_stack(name=stack.name) == stack
        assert mgmt.does_stack_exist(stack.name)
        assert not mgmt.does_stack_exist("some_fake_name")

    if isinstance(vm, EC2Instance):
        log.info("Testing ec2 instance tags")
        vm.set_tag('key1', 'somedata')
        assert vm.get_tag_value('key1') == 'somedata'
        vm.unset_tag('key1', 'somedata')
        assert vm.get_tag_value('key1') is None

    if isinstance(template, EC2Image):
        log.info("Testing ec2 image tags")
        template.set_tag('key1', 'somedata')
        assert template.get_tag_value('key1') == 'somedata'
        template.unset_tag('key1', 'somedata')
        assert template.get_tag_value('key1') is None

    log.info("Listing VMs")
    vms = mgmt.list_vms()
    assert [repr(v) for v in vms]
    assert str(vms[0])

    assert template.name
    assert template.uuid
    assert template.exists

    templates = mgmt.list_templates()
    assert [repr(tmp) for tmp in templates]
    assert str(templates[0])
    try:
        assert template in mgmt.find_templates(name=template.name)
    except NotImplementedError:
        pass
    assert template in mgmt.list_templates()
    try:
        assert mgmt.get_template(template.name) == template
    except MultipleItemsError:
        pass

    assert vm

    assert isinstance(vm.creation_time, datetime.datetime)

    assert vm.exists
    try:
        assert vm.get_hardware_configuration()
    except NotImplementedError:
        pass

    assert vm.in_steady_state
    assert vm.state in VmState.valid_states()

    if isinstance(mgmt, wrapanapi.systems.OpenstackSystem):
        pools = mgmt.api.floating_ip_pools.list()
        pool_name = pools[0].name
        vm.assign_floating_ip(pool_name)

    wait_for(lambda: vm.ip, timeout="1m", delay=1)

    if isinstance(mgmt, wrapanapi.systems.OpenstackSystem):
        vm.unassign_floating_ip()
        assert not vm.ip

    try:
        new_name = 'test-{}'.format(fauxfactory.gen_alphanumeric(6)).lower()
        vm.rename(new_name)
        assert vm.name == new_name
    except NotImplementedError:
        pass

    if isinstance(vm, wrapanapi.entities.Instance):
        assert vm.type

    vm.ensure_state(VmState.STOPPED)

    vm.ensure_state(VmState.RUNNING)

    log.info("Checking state changes")
    if vm.system.can_pause:
        vm.pause()
        assert vm.is_paused
        vm.ensure_state(VmState.RUNNING)

    if vm.system.can_suspend:
        vm.suspend()
        assert vm.is_suspended
        vm.ensure_state(VmState.RUNNING)

    assert vm.stop()
    assert vm.is_stopped
    assert vm.start()
    assert vm.is_running

    assert vm.restart()
    assert vm.is_running

    try:
        assert vm in mgmt.find_vms(name=vm.name)
    except NotImplementedError:
        pass
    assert vm in mgmt.list_vms()
    assert mgmt.get_vm(vm.name) == vm

    log.info("Cleaning up VM")
    assert vm.cleanup()

    assert not vm.exists
    assert vm not in mgmt.list_vms()
<commit_msg>fix lint for comment<commit_after>"""
Simple sanity test for VM/template systems

TODO: Possibly mock this out, remove reliance on 'cfme', etc.

If running within a cfme venv, disable the cfme plugins like so:
   $ pytest test_vm_and_template_systems.py -p no:cfme -s
"""

import datetime
import logging

import pytest
import fauxfactory
from wait_for import wait_for

import wrapanapi
from wrapanapi import VmState
from wrapanapi.entities import StackMixin
from wrapanapi.systems.ec2 import EC2Image, EC2Instance, StackStates
from wrapanapi.exceptions import MultipleItemsError

log = logging.getLogger('wrapanapi.tests.test_vm_and_template_systems')

logging.basicConfig(level=logging.INFO)

PROVIDER_KEYS_LIST = ['ec2west']
#    'rhos11', 'vsphere65-nested', 'scvmm', 'azure', 'gce_central', 'ec2west', 'rhv41'
# TODO test against all provider keys

@pytest.fixture(params=PROVIDER_KEYS_LIST)
def provider_crud(request):
    providers = pytest.importorskip('cfme.utils.providers')
    log.info("Using provider key: %s", request.param)
    return providers.get_crud(request.param)

@pytest.fixture
def test_template(provider_crud):
    deploy_args = {}
    try:
        template_name = provider_crud.data['templates']['small_template']['name']
        deploy_args.update({'template': template_name})
    except KeyError:
        raise KeyError('small_template not defined for Provider {} in cfme_data.yaml'
                       .format(provider_crud.data['name']))
    log.info(
        "Using template %s on provider %s",
        deploy_args['template'], provider_crud.data['name']
    )

    deploy_args.update(vm_name='TBD')
    deploy_args.update(provider_crud.deployment_helper(deploy_args))
    log.debug("Deploy args: %s", deploy_args)

    if isinstance(provider_crud.mgmt, wrapanapi.systems.AzureSystem):
        template = provider_crud.mgmt.get_template(
            template_name, container=deploy_args['template_container'])
    else:
        template = provider_crud.mgmt.get_template(template_name)

    return template

@pytest.yield_fixture
def test_vm(provider_crud, test_template):
    deploy_args = {}
    try:
        template_name = provider_crud.data['templates']['small_template']['name']
        deploy_args.update({'template': template_name})
    except KeyError:
        raise KeyError('small_template not defined for Provider {} in cfme_data.yaml'
                       .format(provider_crud.data['name']))

    vm_name = 'test-{}'.format(fauxfactory.gen_alphanumeric(6)).lower()
    log.info("Deploying VM %s", vm_name)

    deploy_args.update(vm_name=vm_name)
    deploy_args.update(provider_crud.deployment_helper(deploy_args))
    log.debug("Deploy args: %s", deploy_args)

    vm = test_template.deploy(timeout=900, **deploy_args)

    yield vm

    try:
        vm.cleanup()
    except Exception:
        log.exception("Failed to cleanup vm")

def test_sanity(provider_crud, test_template, test_vm):

    template = test_template
    vm = test_vm
    mgmt = provider_crud.mgmt

    if isinstance(mgmt, StackMixin):
        stacks = mgmt.list_stacks(StackStates.ALL)
        assert [repr(stack) for stack in stacks]
        assert str(stacks[0])
        stack = stacks[0]
        assert stack in mgmt.find_stacks(name=stack.name)
        assert mgmt.get_stack(name=stack.name) == stack
        assert mgmt.does_stack_exist(stack.name)
        assert not mgmt.does_stack_exist("some_fake_name")

    if isinstance(vm, EC2Instance):
        log.info("Testing ec2 instance tags")
        vm.set_tag('key1', 'somedata')
        assert vm.get_tag_value('key1') == 'somedata'
        vm.unset_tag('key1', 'somedata')
        assert vm.get_tag_value('key1') is None

    if isinstance(template, EC2Image):
        log.info("Testing ec2 image tags")
        template.set_tag('key1', 'somedata')
        assert template.get_tag_value('key1') == 'somedata'
        template.unset_tag('key1', 'somedata')
        assert template.get_tag_value('key1') is None

    log.info("Listing VMs")
    vms = mgmt.list_vms()
    assert [repr(v) for v in vms]
    assert str(vms[0])

    assert template.name
    assert template.uuid
    assert template.exists

    templates = mgmt.list_templates()
    assert [repr(tmp) for tmp in templates]
    assert str(templates[0])
    try:
        assert template in mgmt.find_templates(name=template.name)
    except NotImplementedError:
        pass
    assert template in mgmt.list_templates()
    try:
        assert mgmt.get_template(template.name) == template
    except MultipleItemsError:
        pass

    assert vm

    assert isinstance(vm.creation_time, datetime.datetime)

    assert vm.exists
    try:
        assert vm.get_hardware_configuration()
    except NotImplementedError:
        pass

    assert vm.in_steady_state
    assert vm.state in VmState.valid_states()

    if isinstance(mgmt, wrapanapi.systems.OpenstackSystem):
        pools = mgmt.api.floating_ip_pools.list()
        pool_name = pools[0].name
        vm.assign_floating_ip(pool_name)

    wait_for(lambda: vm.ip, timeout="1m", delay=1)

    if isinstance(mgmt, wrapanapi.systems.OpenstackSystem):
        vm.unassign_floating_ip()
        assert not vm.ip

    try:
        new_name = 'test-{}'.format(fauxfactory.gen_alphanumeric(6)).lower()
        vm.rename(new_name)
        assert vm.name == new_name
    except NotImplementedError:
        pass

    if isinstance(vm, wrapanapi.entities.Instance):
        assert vm.type

    vm.ensure_state(VmState.STOPPED)

    vm.ensure_state(VmState.RUNNING)

    log.info("Checking state changes")
    if vm.system.can_pause:
        vm.pause()
        assert vm.is_paused
        vm.ensure_state(VmState.RUNNING)

    if vm.system.can_suspend:
        vm.suspend()
        assert vm.is_suspended
        vm.ensure_state(VmState.RUNNING)

    assert vm.stop()
    assert vm.is_stopped
    assert vm.start()
    assert vm.is_running

    assert vm.restart()
    assert vm.is_running

    try:
        assert vm in mgmt.find_vms(name=vm.name)
    except NotImplementedError:
        pass
    assert vm in mgmt.list_vms()
    assert mgmt.get_vm(vm.name) == vm

    log.info("Cleaning up VM")
    assert vm.cleanup()

    assert not vm.exists
    assert vm not in mgmt.list_vms()
<|endoftext|>


<commit_before>#!/usr/bin/python
# -*- coding: utf-8 -*-

from ujson import loads
from tests.unit.base import ApiTestCase
from preggy import expect
from tornado.testing import gen_test

from tests.fixtures import ReviewFactory, PageFactory, DomainFactory, KeyFactory, ViolationFactory
from holmes.models import Key, Violation

class TestMostCommonViolationsHandler(ApiTestCase):

    @gen_test
    def test_can_get_most_common_violations(self):
        self.db.query(Violation).delete()

        review = ReviewFactory.create()

        for i in range(5):
            key = Key.get_or_create(self.db, 'violation1')
            review.add_violation(key, 'value', 100, review.domain)

        for j in range(2):
            key = Key.get_or_create(self.db, 'violation2')
            review.add_violation(key, 'value', 300, review.domain)

        self.db.flush()

        response = yield self.http_client.fetch(
            self.get_url('/most-common-violations/')
        )

        violations = loads(response.body)

        expect(response.code).to_equal(200)
        expect(violations).to_be_like([
            {'count': 5, 'name': 'undefined', 'category': 'undefined', 'key': 'violation1'},
            {'count': 2, 'name': 'undefined', 'category': 'undefined', 'key': 'violation2'}
        ])

        self.db.query(Violation).delete()

        response = yield self.http_client.fetch(
            self.get_url('/most-common-violations/')
        )

        violations_from_cache = loads(response.body)

        expect(response.code).to_equal(200)
        expect(violations_from_cache).to_be_like(violations)

class TestViolationHandler(ApiTestCase):

    @gen_test
    def test_can_get_violation_by_key_name(self):
        domains = [DomainFactory.create(
            name='g%s.com' % chr(i),
            url='http://g%s.com/' % chr(i)
        ) for i in xrange(ord('a'), ord('d'))]

        pages = [PageFactory.create(
            domain=domains[i % 3],
            url='%s%d' % (domains[i % 3].url, i % 2)
        ) for i in xrange(6)]

        for i, page in enumerate(pages):
            ReviewFactory.create(page=page, is_active=True, number_of_violations=i)

        self.db.flush()

        self.server.application.violation_definitions = {
            'key.%s' % i: {
                'title': 'title.%s' % i,
                'category': 'category.%s' % (i % 3),
                'key': Key.get_or_create(self.db, 'key.%d' % i, 'category.%d' % (i % 3))
            } for i in xrange(6)
        }

        response = yield self.http_client.fetch(
            self.get_url('/violation/key.1')
        )
        violations = loads(response.body)
        expect(response.code).to_equal(200)
        expect(violations).to_length(3)
        expect(violations['title']).to_equal('title.1')
        expect(violations['reviews']).to_length(4)
        expect(violations['reviewsCount']).to_equal(4)

        response = yield self.http_client.fetch(
            self.get_url('/violation/key.1?page_size=2&current_page=1')
        )
        violations = loads(response.body)
        expect(response.code).to_equal(200)
        expect(violations).to_length(3)
        expect(violations['title']).to_equal('title.1')
        expect(violations['reviews']).to_length(2)
        expect(violations['reviewsCount']).to_equal(4)

        response = yield self.http_client.fetch(
            self.get_url('/violation/key.1?page_filter=1')
        )
        violations = loads(response.body)
        expect(response.code).to_equal(200)
        expect(violations).to_length(3)
        expect(violations['title']).to_equal('title.1')
        expect(violations['reviews']).to_length(2)
        expect(violations['reviewsCount']).to_equal(2)

        response = yield self.http_client.fetch(
            self.get_url('/violation/key.1?domain_filter=gc.com')
        )
        violations = loads(response.body)
        expect(response.code).to_equal(200)
        expect(violations).to_length(3)
        expect(violations['title']).to_equal('title.1')
        expect(violations['reviews']).to_length(2)
        expect(violations['reviewsCount']).to_equal(8)

        response = yield self.http_client.fetch(
            self.get_url('/violation/key.1?domain_filter=foobar')
        )
        violations = loads(response.body)
        expect(response.code).to_equal(200)
        expect(violations).to_length(3)
        expect(violations['title']).to_equal('title.1')
        expect(violations['reviews']).to_length(4)
        expect(violations['reviewsCount']).to_equal(4)

        response = yield self.http_client.fetch(
            self.get_url('/violation/key.1?domain_filter=gc.com&page_filter=1')
        )
        violations = loads(response.body)
        expect(response.code).to_equal(200)
        expect(violations).to_length(3)
        expect(violations['title']).to_equal('title.1')
        expect(violations['reviews']).to_length(1)
        expect(violations['reviewsCount']).to_equal(1)

    @gen_test
    def test_can_get_blacklist_domains(self):
        key = KeyFactory.create(name='blacklist.domains')

        for i in xrange(3):
            for j in xrange(i + 1):
                ViolationFactory.create(
                    key=key,
                    value=[
                        'http://www.blacklist-domain-%d.com/' % i,
                        'http://blacklist-domain-%d.com/' % i
                    ]
                )
                ViolationFactory.create(
                    key=key,
                    value=['http://www.blacklist-domain-%d.com/' % i]
                )

        self.db.flush()

        self.server.application.violation_definitions = {
            'blacklist.domains': {
                'title': 'title',
                'category': 'category',
                'key': key
            }
        }

        response = yield self.http_client.fetch(
            self.get_url('/violation/blacklist.domains')
        )
        expect(response.code).to_equal(200)

        violation = loads(response.body)
        expect(violation['details']).to_length(3)
        expect(violation['details']).to_be_like([
            {'count': 9, 'domain': 'blacklist-domain-2.com'},
            {'count': 6, 'domain': 'blacklist-domain-1.com'},
            {'count': 3, 'domain': 'blacklist-domain-0.com'}
        ])

class TestViolationDomainsHandler(ApiTestCase):

    @gen_test
    def test_can_get_by_key_name_domains(self):
        domains = [DomainFactory.create(name='g%d.com' % i) for i in xrange(2)]
        keys = [KeyFactory.create(name='random.fact.%s' % i) for i in xrange(3)]

        for i in range(3):
            for j in range(i + 1):
                ViolationFactory.create(
                    key=keys[i],
                    domain=domains[j % 2]
                )

        self.db.flush()

        self.server.application.violation_definitions = {
            'random.fact.%s' % i: {
                'title': 'SEO',
                'category': 'SEO',
                'key': keys[i]
            } for i in xrange(3)
        }

        response = yield self.http_client.fetch(
            self.get_url('/violation/%s/domains' % keys[2].name)
        )

        violation = loads(response.body)

        expected_violation = {
            'domains': [
                {'name': 'g0.com', 'count': 2},
                {'name': 'g1.com', 'count': 1}
            ],
            'total': 3,
            'title': 'SEO'
        }

        expect(response.code).to_equal(200)
        expect(violation).to_length(3)
        expect(violation['domains']).to_length(2)
        expect(violation).to_be_like(expected_violation)
<commit_msg>Set correct url of test<commit_after>#!/usr/bin/python
# -*- coding: utf-8 -*-

from ujson import loads
from tests.unit.base import ApiTestCase
from preggy import expect
from tornado.testing import gen_test

from tests.fixtures import ReviewFactory, PageFactory, DomainFactory, KeyFactory, ViolationFactory
from holmes.models import Key, Violation

class TestMostCommonViolationsHandler(ApiTestCase):

    @gen_test
    def test_can_get_most_common_violations(self):
        self.db.query(Violation).delete()

        review = ReviewFactory.create()

        for i in range(5):
            key = Key.get_or_create(self.db, 'violation1')
            review.add_violation(key, 'value', 100, review.domain)

        for j in range(2):
            key = Key.get_or_create(self.db, 'violation2')
            review.add_violation(key, 'value', 300, review.domain)

        self.db.flush()

        response = yield self.http_client.fetch(
            self.get_url('/most-common-violations/')
        )

        violations = loads(response.body)

        expect(response.code).to_equal(200)
        expect(violations).to_be_like([
            {'count': 5, 'name': 'undefined', 'category': 'undefined', 'key': 'violation1'},
            {'count': 2, 'name': 'undefined', 'category': 'undefined', 'key': 'violation2'}
        ])

        self.db.query(Violation).delete()

        response = yield self.http_client.fetch(
            self.get_url('/most-common-violations/')
        )

        violations_from_cache = loads(response.body)

        expect(response.code).to_equal(200)
        expect(violations_from_cache).to_be_like(violations)

class TestViolationHandler(ApiTestCase):

    @gen_test
    def test_can_get_violation_by_key_name(self):
        domains = [DomainFactory.create(
            name='g%s.com' % chr(i),
            url='http://g%s.com/' % chr(i)
        ) for i in xrange(ord('a'), ord('d'))]

        pages = [PageFactory.create(
            domain=domains[i % 3],
            url='%s%d' % (domains[i % 3].url, i % 2)
        ) for i in xrange(6)]

        for i, page in enumerate(pages):
            ReviewFactory.create(page=page, is_active=True, number_of_violations=i)

        self.db.flush()

        self.server.application.violation_definitions = {
            'key.%s' % i: {
                'title': 'title.%s' % i,
                'category': 'category.%s' % (i % 3),
                'key': Key.get_or_create(self.db, 'key.%d' % i, 'category.%d' % (i % 3))
            } for i in xrange(6)
        }

        response = yield self.http_client.fetch(
            self.get_url('/violation/key.1')
        )
        violations = loads(response.body)
        expect(response.code).to_equal(200)
        expect(violations).to_length(3)
        expect(violations['title']).to_equal('title.1')
        expect(violations['reviews']).to_length(4)
        expect(violations['reviewsCount']).to_equal(4)

        response = yield self.http_client.fetch(
            self.get_url('/violation/key.1?page_size=2&current_page=1')
        )
        violations = loads(response.body)
        expect(response.code).to_equal(200)
        expect(violations).to_length(3)
        expect(violations['title']).to_equal('title.1')
        expect(violations['reviews']).to_length(2)
        expect(violations['reviewsCount']).to_equal(4)

        response = yield self.http_client.fetch(
            self.get_url('/violation/key.1?page_filter=1')
        )
        violations = loads(response.body)
        expect(response.code).to_equal(200)
        expect(violations).to_length(3)
        expect(violations['title']).to_equal('title.1')
        expect(violations['reviews']).to_length(2)
        expect(violations['reviewsCount']).to_equal(2)

        response = yield self.http_client.fetch(
            self.get_url('/violation/key.1?domain_filter=gc.com')
        )
        violations = loads(response.body)
        expect(response.code).to_equal(200)
        expect(violations).to_length(3)
        expect(violations['title']).to_equal('title.1')
        expect(violations['reviews']).to_length(2)
        expect(violations['reviewsCount']).to_equal(8)

        response = yield self.http_client.fetch(
            self.get_url('/violation/key.1?domain_filter=foobar')
        )
        violations = loads(response.body)
        expect(response.code).to_equal(200)
        expect(violations).to_length(3)
        expect(violations['title']).to_equal('title.1')
        expect(violations['reviews']).to_length(4)
        expect(violations['reviewsCount']).to_equal(4)

        response = yield self.http_client.fetch(
            self.get_url('/violation/key.1?domain_filter=gc.com&page_filter=1')
        )
        violations = loads(response.body)
        expect(response.code).to_equal(200)
        expect(violations).to_length(3)
        expect(violations['title']).to_equal('title.1')
        expect(violations['reviews']).to_length(1)
        expect(violations['reviewsCount']).to_equal(1)

    @gen_test
    def test_can_get_blacklist_domains(self):
        key = KeyFactory.create(name='blacklist.domains')

        for i in xrange(3):
            for j in xrange(i + 1):
                ViolationFactory.create(
                    key=key,
                    value=[
                        'http://www.blacklist-domain-%d.com/' % i,
                        'http://blacklist-domain-%d.com/' % i
                    ]
                )
                ViolationFactory.create(
                    key=key,
                    value=['http://www.blacklist-domain-%d.com/' % i]
                )

        self.db.flush()

        self.server.application.violation_definitions = {
            'blacklist.domains': {
                'title': 'title',
                'category': 'category',
                'key': key
            }
        }

        response = yield self.http_client.fetch(
            self.get_url('/violation/blacklist.domains/domains')
        )
        expect(response.code).to_equal(200)

        violation = loads(response.body)
        expect(violation['details']).to_length(3)
        expect(violation['details']).to_be_like([
            {'count': 9, 'domain': 'blacklist-domain-2.com'},
            {'count': 6, 'domain': 'blacklist-domain-1.com'},
            {'count': 3, 'domain': 'blacklist-domain-0.com'}
        ])

class TestViolationDomainsHandler(ApiTestCase):

    @gen_test
    def test_can_get_by_key_name_domains(self):
        domains = [DomainFactory.create(name='g%d.com' % i) for i in xrange(2)]
        keys = [KeyFactory.create(name='random.fact.%s' % i) for i in xrange(3)]

        for i in range(3):
            for j in range(i + 1):
                ViolationFactory.create(
                    key=keys[i],
                    domain=domains[j % 2]
                )

        self.db.flush()

        self.server.application.violation_definitions = {
            'random.fact.%s' % i: {
                'title': 'SEO',
                'category': 'SEO',
                'key': keys[i]
            } for i in xrange(3)
        }

        response = yield self.http_client.fetch(
            self.get_url('/violation/%s/domains' % keys[2].name)
        )

        violation = loads(response.body)

        expected_violation = {
            'domains': [
                {'name': 'g0.com', 'count': 2},
                {'name': 'g1.com', 'count': 1}
            ],
            'total': 3,
            'title': 'SEO'
        }

        expect(response.code).to_equal(200)
        expect(violation).to_length(3)
        expect(violation['domains']).to_length(2)
        expect(violation).to_be_like(expected_violation)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
'''
    :codeauthor: :email:`Rupesh Tare <rupesht@saltstack.com>`
'''

# Import Python Libs
from __future__ import absolute_import

# Import Salt Testing Libs
from tests.support.unit import TestCase, skipIf
from tests.support.mock import (
    patch,
    NO_MOCK,
    NO_MOCK_REASON
)

# Import Salt Libs
import salt.modules.mod_random as mod_random
import salt.utils.pycrypto
from salt.exceptions import SaltInvocationError

# Globals
mod_random.__grains__ = {}
mod_random.__salt__ = {}
mod_random.__context__ = {}
mod_random.__opts__ = {}

def _test_hashlib():
    try:
        import hashlib
    except ImportError:
        return False
    if not hasattr(hashlib, 'algorithms'):
        return False
    else:
        return True

SUPPORTED_HASHLIB = _test_hashlib()

@skipIf(not SUPPORTED_HASHLIB, 'Hashlib does not contain needed functionality')
@skipIf(NO_MOCK, NO_MOCK_REASON)
class ModrandomTestCase(TestCase):
    '''
    Test cases for salt.modules.mod_random
    '''
    def test_hash(self):
        '''
        Test for Encodes a value with the specified encoder.
        '''
        self.assertEqual(mod_random.hash('value')[0:4], 'ec2c')

        self.assertRaises(SaltInvocationError,
                          mod_random.hash, 'value', 'algorithm')

    def test_str_encode(self):
        '''
        Test for The value to be encoded.
        '''
        self.assertRaises(SaltInvocationError,
                          mod_random.str_encode, 'None', 'abc')

        self.assertRaises(SaltInvocationError,
                          mod_random.str_encode, None)

        self.assertEqual(mod_random.str_encode('A'), 'QQ==\n')

    def test_get_str(self):
        '''
        Test for Returns a random string of the specified length.
        '''
        with patch.object(salt.utils.pycrypto,
                          'secure_password', return_value='A'):
            self.assertEqual(mod_random.get_str(), 'A')

    def test_shadow_hash(self):
        '''
        Test for Generates a salted hash suitable for /etc/shadow.
        '''
        with patch.object(salt.utils.pycrypto,
                          'gen_hash', return_value='A'):
            self.assertEqual(mod_random.shadow_hash(), 'A')
<commit_msg>Proper mocking. Py3 Compat.<commit_after># -*- coding: utf-8 -*-
'''
    :codeauthor: :email:`Rupesh Tare <rupesht@saltstack.com>`
'''

# Import Python Libs
from __future__ import absolute_import

# Import Salt Testing Libs
from tests.support.mixins import LoaderModuleMockMixin
from tests.support.unit import TestCase, skipIf
from tests.support.mock import (
    patch,
    NO_MOCK,
    NO_MOCK_REASON
)

# Import Salt Libs
import salt.modules.mod_random as mod_random
import salt.utils.pycrypto
from salt.exceptions import SaltInvocationError

# Import 3rd-party libs
import salt.ext.six as six

def _test_hashlib():
    try:
        import hashlib
    except ImportError:
        return False

    if six.PY2:
        algorithms_attr_name = 'algorithms'
    else:
        algorithms_attr_name = 'algorithms_guaranteed'

    if not hasattr(hashlib, algorithms_attr_name):
        return False
    else:
        return True

SUPPORTED_HASHLIB = _test_hashlib()

@skipIf(not SUPPORTED_HASHLIB, 'Hashlib does not contain needed functionality')
@skipIf(NO_MOCK, NO_MOCK_REASON)
class ModrandomTestCase(TestCase, LoaderModuleMockMixin):
    '''
    Test cases for salt.modules.mod_random
    '''
    def setup_loader_modules(self):
        return {mod_random: {}}

    def test_hash(self):
        '''
        Test for Encodes a value with the specified encoder.
        '''
        self.assertEqual(mod_random.hash('value')[0:4], 'ec2c')

        self.assertRaises(SaltInvocationError,
                          mod_random.hash, 'value', 'algorithm')

    def test_str_encode(self):
        '''
        Test for The value to be encoded.
        '''
        self.assertRaises(SaltInvocationError,
                          mod_random.str_encode, 'None', 'abc')

        self.assertRaises(SaltInvocationError,
                          mod_random.str_encode, None)

        if six.PY2:
            self.assertEqual(mod_random.str_encode('A'), 'QQ==\n')
        else:
            # We're using the base64 module which does not include the trailing new line
            self.assertEqual(mod_random.str_encode('A'), 'QQ==')

    def test_get_str(self):
        '''
        Test for Returns a random string of the specified length.
        '''
        with patch.object(salt.utils.pycrypto,
                          'secure_password', return_value='A'):
            self.assertEqual(mod_random.get_str(), 'A')

    def test_shadow_hash(self):
        '''
        Test for Generates a salted hash suitable for /etc/shadow.
        '''
        with patch.object(salt.utils.pycrypto,
                          'gen_hash', return_value='A'):
            self.assertEqual(mod_random.shadow_hash(), 'A')
<|endoftext|>


<commit_before>
import random
from mock import MagicMock, AsyncMock, create_autospec, patch

from tornado.testing import AsyncTestCase, gen_test
from tornado.gen import coroutine

from delivery.services.external_program_service import ExternalProgramService
from delivery.services.dds_service import DDSService
from delivery.models.db_models import DeliveryOrder, StagingOrder, StagingStatus, DeliveryStatus, DDSProject
from delivery.models.execution import ExecutionResult, Execution
from delivery.exceptions import InvalidStatusException, CannotParseMoverOutputException

from tests.test_utils import MockIOLoop, assert_eventually_equals

class TestDDSService(AsyncTestCase):

    def setUp(self):

        example_dds_project_ls_stdout = """[
  {
    "Last updated": "Thu, 03 Mar 2022 11:46:31 CET",
    "PI": "Dungeon master",
    "Project ID": "snpseq00001",
    "Size": 26956752654,
    "Status": "In Progress",
    "Title": "Bullywug anatomy"
  },
  {
    "Last updated": "Thu, 03 Mar 2022 10:34:05 CET",
    "PI": "matas618",
    "Project ID": "snpseq00002",
    "Size": 0,
    "Status": "In Progress",
    "Title": "Site admins project"
  }
]
        """

        self.mock_mover_runner = create_autospec(ExternalProgramService)
        mock_process = MagicMock()
        mock_execution = Execution(pid=random.randint(1, 1000), process_obj=mock_process)
        self.mock_mover_runner.run.return_value = mock_execution

        @coroutine
        def wait_as_coroutine(x):
            return ExecutionResult(stdout=example_dds_project_ls_stdout, stderr="", status_code=0)

        self.mock_mover_runner.wait_for_execution = wait_as_coroutine

        self.mock_staging_service = MagicMock()
        self.mock_delivery_repo = MagicMock()
        self.mock_dds_project_repo = MagicMock()

        self.delivery_order = DeliveryOrder(
                id=1,
                delivery_source="/staging/dir/bar",
                delivery_project="snpseq00001",
                )

        self.mock_delivery_repo.create_delivery_order.return_value = self.delivery_order
        self.mock_delivery_repo.get_delivery_order_by_id.return_value = self.delivery_order

        self.mock_session_factory = MagicMock()
        self.mock_dds_config = {'token_path': '/foo/bar/auth', 'log_path': '/foo/bar/log'}
        self.dds_service = DDSService(
                external_program_service=ExternalProgramService(),
                staging_service=self.mock_staging_service,
                delivery_repo=self.mock_delivery_repo,
                dds_project_repo=self.mock_dds_project_repo,
                session_factory=self.mock_session_factory,
                dds_conf=self.mock_dds_config
                )

        # Inject separate external runner instances for the tests, since they need to return
        # different information
        self.dds_service.mover_external_program_service = self.mock_mover_runner

        super(TestDDSService, self).setUp()

    @gen_test
    def test_deliver_by_staging_id(self):
        source = '/foo/bar'
        staging_target = '/staging/dir/bar'
        staging_order = StagingOrder(source=source, staging_target=staging_target)
        staging_order.status = StagingStatus.staging_successful
        self.mock_staging_service.get_stage_order_by_id.return_value = staging_order

        self.mock_staging_service.get_delivery_order_by_id.return_value = self.delivery_order

        with patch('shutil.rmtree') as mock_rmtree:
            res = yield self.dds_service.deliver_by_staging_id(
                    staging_id=1,
                    delivery_project='snpseq00001',
                    token_path='token_path',
                    md5sum_file='md5sum_file')
            mock_rmtree.assert_called_once_with(staging_target)

        def _get_delivery_order():
            return self.delivery_order.delivery_status
        assert_eventually_equals(self, 1, _get_delivery_order, DeliveryStatus.delivery_successful)
        self.mock_mover_runner.run.assert_called_with([
            'dds',
            '--token-path', 'token_path',
            '--log-file', '/foo/bar/log',
            'data', 'put',
            '--source', '/staging/dir/bar',
            '--project', 'snpseq00001',
            '--silent'
            ])

    @gen_test
    def test_deliver_by_staging_id_raises_on_non_existent_stage_id(self):
        self.mock_staging_service.get_stage_order_by_id.return_value = None

        with self.assertRaises(InvalidStatusException):

            yield self.dds_service.deliver_by_staging_id(
                    staging_id=1,
                    delivery_project='snpseq00001',
                    md5sum_file='md5sum_file',
                    token_path='token_path',
                    )

    @gen_test
    def test_deliver_by_staging_id_raises_on_non_successful_stage_id(self):

        staging_order = StagingOrder()
        staging_order.status = StagingStatus.staging_failed
        self.mock_staging_service.get_stage_order_by_id.return_value = staging_order

        with self.assertRaises(InvalidStatusException):

            yield self.dds_service.deliver_by_staging_id(
                    staging_id=1,
                    delivery_project='snpseq00001',
                    md5sum_file='md5sum_file',
                    token_path='token_path',
                    )

    def test_delivery_order_by_id(self):
        delivery_order = DeliveryOrder(id=1,
                                       delivery_source='src',
                                       delivery_project='snpseq00001',
                                       delivery_status=DeliveryStatus.delivery_in_progress,
                                       staging_order_id=11,
                                       md5sum_file='file')
        self.mock_delivery_repo.get_delivery_order_by_id.return_value = delivery_order
        actual = self.dds_service.get_delivery_order_by_id(1)
        self.assertEqual(actual.id, 1)

    def test_possible_to_delivery_by_staging_id_and_skip_mover(self):

        staging_order = StagingOrder(source='/foo/bar', staging_target='/staging/dir/bar')
        staging_order.status = StagingStatus.staging_successful
        self.mock_staging_service.get_stage_order_by_id.return_value = staging_order

        self.mock_staging_service.get_delivery_order_by_id.return_value = self.delivery_order

        self.dds_service.deliver_by_staging_id(
                staging_id=1,
                delivery_project='snpseq00001',
                md5sum_file='md5sum_file',
                token_path='token_path',
                skip_mover=True,
                )

        def _get_delivery_order():
            return self.delivery_order.delivery_status
        assert_eventually_equals(self, 1, _get_delivery_order, DeliveryStatus.delivery_skipped)

    def test_parse_dds_project_id(self):
        dds_output = """Current user: bio
Project created with id: snpseq00003
User forskare was associated with Project snpseq00003 as Owner=True. An e-mail notification has not been sent.
Invitation sent to email@adress.com. The user should have a valid account to be added to a
project"""

        self.assertEqual(DDSService._parse_dds_project_id(dds_output), "snpseq00003")

    @gen_test
    def test_create_project(self):
        self.mock_dds_project_repo.project_exists.return_value = False

        project_name = "AA-1221"
        project_metadata = {
                "description": "Dummy project",
                "pi": "alex@doe.com",
                "researchers": ["robin@doe.com", "kim@doe.com"],
                "owners": ["alex@doe.com"],
                "non-sensitive": False,
                "token_path": "/foo/bar/auth",
                }

        with patch(
                'delivery.services.external_program_service'
                '.ExternalProgramService.run_and_wait',
                new_callable=AsyncMock) as mock_run,\
                patch('delivery.services.dds_service.DDSService._parse_dds_project_id') as mock_parse_dds_project_id:
            mock_run.return_value.status_code = 0
            mock_parse_dds_project_id.return_value = "snpseq00001"

            yield self.dds_service.create_dds_project(project_name, project_metadata)

            mock_run.assert_called_once_with([
                'dds',
                '--token-path', '/foo/bar/auth',
                '--log-file', '/foo/bar/log',
                'project', 'create',
                '--title', project_name,
                '--description', project_metadata['description'],
                '-pi', project_metadata['pi'],
                '--owner', project_metadata['owners'][0],
                '--researcher', project_metadata['researchers'][0],
                '--researcher', project_metadata['researchers'][1],
                ])
            self.mock_dds_project_repo.add_dds_project\
                    .assert_called_once_with(
                            project_name=project_name,
                            dds_project_id=mock_parse_dds_project_id.return_value)
<commit_msg>Remove leftovers from previous tests<commit_after>
import random
from mock import MagicMock, AsyncMock, create_autospec, patch

from tornado.testing import AsyncTestCase, gen_test
from tornado.gen import coroutine

from delivery.services.external_program_service import ExternalProgramService
from delivery.services.dds_service import DDSService
from delivery.models.db_models import DeliveryOrder, StagingOrder, StagingStatus, DeliveryStatus, DDSProject
from delivery.models.execution import ExecutionResult, Execution
from delivery.exceptions import InvalidStatusException, CannotParseMoverOutputException

from tests.test_utils import MockIOLoop, assert_eventually_equals

class TestDDSService(AsyncTestCase):

    def setUp(self):

        example_dds_project_ls_stdout = """[
  {
    "Last updated": "Thu, 03 Mar 2022 11:46:31 CET",
    "PI": "Dungeon master",
    "Project ID": "snpseq00001",
    "Size": 26956752654,
    "Status": "In Progress",
    "Title": "Bullywug anatomy"
  },
  {
    "Last updated": "Thu, 03 Mar 2022 10:34:05 CET",
    "PI": "matas618",
    "Project ID": "snpseq00002",
    "Size": 0,
    "Status": "In Progress",
    "Title": "Site admins project"
  }
]
        """

        self.mock_mover_runner = create_autospec(ExternalProgramService)
        mock_process = MagicMock()
        mock_execution = Execution(pid=random.randint(1, 1000), process_obj=mock_process)
        self.mock_mover_runner.run.return_value = mock_execution

        @coroutine
        def wait_as_coroutine(x):
            return ExecutionResult(stdout=example_dds_project_ls_stdout, stderr="", status_code=0)

        self.mock_mover_runner.wait_for_execution = wait_as_coroutine

        self.mock_staging_service = MagicMock()
        self.mock_delivery_repo = MagicMock()
        self.mock_dds_project_repo = MagicMock()

        self.delivery_order = DeliveryOrder(
                id=1,
                delivery_source="/staging/dir/bar",
                delivery_project="snpseq00001",
                )

        self.mock_delivery_repo.create_delivery_order.return_value = self.delivery_order
        self.mock_delivery_repo.get_delivery_order_by_id.return_value = self.delivery_order

        self.mock_session_factory = MagicMock()
        self.mock_dds_config = {'token_path': '/foo/bar/auth', 'log_path': '/foo/bar/log'}
        self.dds_service = DDSService(
                external_program_service=ExternalProgramService(),
                staging_service=self.mock_staging_service,
                delivery_repo=self.mock_delivery_repo,
                dds_project_repo=self.mock_dds_project_repo,
                session_factory=self.mock_session_factory,
                dds_conf=self.mock_dds_config
                )

        # Inject separate external runner instances for the tests, since they need to return
        # different information
        self.dds_service.mover_external_program_service = self.mock_mover_runner

        super(TestDDSService, self).setUp()

    @gen_test
    def test_deliver_by_staging_id(self):
        source = '/foo/bar'
        staging_target = '/staging/dir/bar'
        staging_order = StagingOrder(source=source, staging_target=staging_target)
        staging_order.status = StagingStatus.staging_successful
        self.mock_staging_service.get_stage_order_by_id.return_value = staging_order

        self.mock_staging_service.get_delivery_order_by_id.return_value = self.delivery_order

        with patch('shutil.rmtree') as mock_rmtree:
            res = yield self.dds_service.deliver_by_staging_id(
                    staging_id=1,
                    delivery_project='snpseq00001',
                    token_path='token_path',
                    md5sum_file='md5sum_file')
            mock_rmtree.assert_called_once_with(staging_target)

        def _get_delivery_order():
            return self.delivery_order.delivery_status
        assert_eventually_equals(self, 1, _get_delivery_order, DeliveryStatus.delivery_successful)
        self.mock_mover_runner.run.assert_called_with([
            'dds',
            '--token-path', 'token_path',
            '--log-file', '/foo/bar/log',
            'data', 'put',
            '--source', '/staging/dir/bar',
            '--project', 'snpseq00001',
            '--silent'
            ])

    @gen_test
    def test_deliver_by_staging_id_raises_on_non_existent_stage_id(self):
        self.mock_staging_service.get_stage_order_by_id.return_value = None

        with self.assertRaises(InvalidStatusException):

            yield self.dds_service.deliver_by_staging_id(
                    staging_id=1,
                    delivery_project='snpseq00001',
                    md5sum_file='md5sum_file',
                    token_path='token_path',
                    )

    @gen_test
    def test_deliver_by_staging_id_raises_on_non_successful_stage_id(self):

        staging_order = StagingOrder()
        staging_order.status = StagingStatus.staging_failed
        self.mock_staging_service.get_stage_order_by_id.return_value = staging_order

        with self.assertRaises(InvalidStatusException):

            yield self.dds_service.deliver_by_staging_id(
                    staging_id=1,
                    delivery_project='snpseq00001',
                    md5sum_file='md5sum_file',
                    token_path='token_path',
                    )

    def test_delivery_order_by_id(self):
        delivery_order = DeliveryOrder(id=1,
                                       delivery_source='src',
                                       delivery_project='snpseq00001',
                                       delivery_status=DeliveryStatus.delivery_in_progress,
                                       staging_order_id=11,
                                       md5sum_file='file')
        self.mock_delivery_repo.get_delivery_order_by_id.return_value = delivery_order
        actual = self.dds_service.get_delivery_order_by_id(1)
        self.assertEqual(actual.id, 1)

    def test_possible_to_delivery_by_staging_id_and_skip_mover(self):

        staging_order = StagingOrder(source='/foo/bar', staging_target='/staging/dir/bar')
        staging_order.status = StagingStatus.staging_successful
        self.mock_staging_service.get_stage_order_by_id.return_value = staging_order

        self.mock_staging_service.get_delivery_order_by_id.return_value = self.delivery_order

        self.dds_service.deliver_by_staging_id(
                staging_id=1,
                delivery_project='snpseq00001',
                md5sum_file='md5sum_file',
                token_path='token_path',
                skip_mover=True,
                )

        def _get_delivery_order():
            return self.delivery_order.delivery_status
        assert_eventually_equals(self, 1, _get_delivery_order, DeliveryStatus.delivery_skipped)

    def test_parse_dds_project_id(self):
        dds_output = """Current user: bio
Project created with id: snpseq00003
User forskare was associated with Project snpseq00003 as Owner=True. An e-mail notification has not been sent.
Invitation sent to email@adress.com. The user should have a valid account to be added to a
project"""

        self.assertEqual(DDSService._parse_dds_project_id(dds_output), "snpseq00003")

    @gen_test
    def test_create_project(self):
        project_name = "AA-1221"
        project_metadata = {
                "description": "Dummy project",
                "pi": "alex@doe.com",
                "researchers": ["robin@doe.com", "kim@doe.com"],
                "owners": ["alex@doe.com"],
                "non-sensitive": False,
                "token_path": "/foo/bar/auth",
                }

        with patch(
                'delivery.services.external_program_service'
                '.ExternalProgramService.run_and_wait',
                new_callable=AsyncMock) as mock_run,\
                patch('delivery.services.dds_service.DDSService._parse_dds_project_id') as mock_parse_dds_project_id:
            mock_run.return_value.status_code = 0
            mock_parse_dds_project_id.return_value = "snpseq00001"

            yield self.dds_service.create_dds_project(project_name, project_metadata)

            mock_run.assert_called_once_with([
                'dds',
                '--token-path', '/foo/bar/auth',
                '--log-file', '/foo/bar/log',
                'project', 'create',
                '--title', project_name,
                '--description', project_metadata['description'],
                '-pi', project_metadata['pi'],
                '--owner', project_metadata['owners'][0],
                '--researcher', project_metadata['researchers'][0],
                '--researcher', project_metadata['researchers'][1],
                ])
            self.mock_dds_project_repo.add_dds_project\
                    .assert_called_once_with(
                            project_name=project_name,
                            dds_project_id=mock_parse_dds_project_id.return_value)
<|endoftext|>