<commit_before># Copyright Hybrid Logic Ltd.  See LICENSE file for details.

"""
Tests for :module:`flocker.node.script`.
"""
import netifaces
import yaml

from pyrsistent import PRecord, field

from jsonschema.exceptions import ValidationError

from zope.interface.verify import verifyObject

from twisted.internet.defer import Deferred
from twisted.python.filepath import FilePath
from twisted.trial.unittest import SynchronousTestCase
from twisted.application.service import Service

from ...volume.testtools import make_volume_options_tests
from ...common.script import ICommandLineScript

from ..script import (
    AgentScript, ContainerAgentOptions,
    AgentServiceFactory, DatasetAgentOptions, validate_configuration,
    _context_factory_and_credential, DatasetServiceFactory,
    AgentService, BackendDescription, get_configuration,
    DeployerType,
)

from .._loop import AgentLoopService
from ...testtools import MemoryCoreReactor, random_name
from ...ca.testtools import get_credential_sets


def setup_config(test, host=u"10.0.0.1", port=1234, name=None):
    """
    Create a configuration file and certificates for a dataset agent in a
    temporary directory.

    Sets ``config`` attribute on the test instance with the path to the
    config file.

    :param test: A ``TestCase`` instance.
    """
    if name is None:
        name = random_name(test)
    ca_set, _ = get_credential_sets()
    scratch_directory = FilePath(test.mktemp())
    scratch_directory.makedirs()
    test.config = scratch_directory.child('dataset-config.yml')
    test.config.setContent(
        yaml.safe_dump({
            u"control-service": {
                u"hostname": host,
                u"port": port,
            },
            u"dataset": {
                u"backend": u"zfs",
                u"name": name,
                # XXX Can't put FilePath in a yaml file (well you can but
                # .... :/)
                u"mount_root": scratch_directory.child(b"mount_root").path,
                u"volume_config_path": scratch_directory.child(
                    b"volume_config.json"
                ).path,
            },
            u"version": 1,
        }))
    ca_set.copy_to(scratch_directory, node=True)
    test.ca_set = ca_set
    test.non_existent_file = scratch_directory.child('missing-config.yml')

deployer = object()


# This should have an explicit interface:
# https://clusterhq.atlassian.net/browse/FLOC-1929
def deployer_factory_stub(**kw):
    if set(kw.keys()) != {"node_uuid", "cluster_uuid", "hostname"}:
        raise TypeError("wrong arguments")
    return deployer


class DummyAgentService(PRecord):
    reactor = field()
    loop_service = field()
    configuration = field()

    @classmethod
    def for_loop_service(cls, loop_service):
        return lambda configuration: cls(
            loop_service=loop_service,
            configuration=configuration,
        )

    def get_api(self):
        return None

    def get_deployer(self, api):
        return None

    def get_loop_service(self, deployer):
        return self.loop_service


class DatasetServiceFactoryTests(SynchronousTestCase):
    """
    Tests for ``DatasetServiceFactory`` using ZFS configuration.
    """
    def setUp(self):
        setup_config(self)

    def test_config_validated(self):
        """
        ``DatasetServiceFactory.get_service`` validates the configuration file.
        """
        self.config.setContent(b"INVALID")

        options = DatasetAgentOptions()
        options.parseOptions([b"--agent-config", self.config.path])

        self.assertRaises(
            ValidationError,
            DatasetServiceFactory().get_service, MemoryCoreReactor(), options,
        )

    def test_missing_configuration_file(self):
        """
        ``DatasetServiceFactory.get_service`` raises an ``IOError`` if the
        given configuration file does not exist.
        """
        options = DatasetAgentOptions()
        options.parseOptions([b"--agent-config", self.non_existent_file.path])

        self.assertRaises(
            IOError,
            DatasetServiceFactory().get_service, MemoryCoreReactor(), options,
        )


def agent_service_setup(test):
    """
    Do some setup common to all of the ``AgentService`` test cases.
    """
    test.ca_set, _ = get_credential_sets()

    test.host = b"192.0.2.5"
    test.port = 54123
    test.reactor = MemoryCoreReactor()

    test.agent_service = AgentService(
        reactor=test.reactor,

        control_service_host=test.host,
        control_service_port=test.port,
        node_credential=test.ca_set.node,
        ca_certificate=test.ca_set.root.credential.certificate,

        backend_name=u"anything",
        api_args={},
    )


class AgentServiceFromConfigurationTests(SynchronousTestCase):
    """
    Tests for ``AgentService.from_configuration``
    """
    def test_initialized(self):
        """
        ``AgentService.from_configuration`` returns an ``AgentService``
        instance with all of its fields initialized from parts of the
        configuration passed in.
        """
        host = b"192.0.2.13"
        port = 2314
        name = u"from_config-test"

        setup_config(self, host=host, port=port, name=name)
        options = DatasetAgentOptions()
        options.parseOptions([b"--agent-config", self.config.path])
        config = get_configuration(options)<commit_msg>Docs and better names<commit_after># Copyright Hybrid Logic Ltd.  See LICENSE file for details.

"""
Tests for :module:`flocker.node.script`.
"""
import netifaces
import yaml

from pyrsistent import PRecord, field

from jsonschema.exceptions import ValidationError

from zope.interface.verify import verifyObject

from twisted.internet.defer import Deferred
from twisted.python.filepath import FilePath
from twisted.trial.unittest import SynchronousTestCase
from twisted.application.service import Service

from ...volume.testtools import make_volume_options_tests
from ...common.script import ICommandLineScript

from ..script import (
    AgentScript, ContainerAgentOptions,
    AgentServiceFactory, DatasetAgentOptions, validate_configuration,
    _context_factory_and_credential, DatasetServiceFactory,
    AgentService, BackendDescription, get_configuration,
    DeployerType,
)

from .._loop import AgentLoopService
from ...testtools import MemoryCoreReactor, random_name
from ...ca.testtools import get_credential_sets


def setup_config(test, control_address=u"10.0.0.1", control_port=1234,
                 name=None):
    """
    Create a configuration file and certificates for a dataset agent in a
    temporary directory.

    Sets ``config`` attribute on the test instance with the path to the config
    file.

    :param test: A ``TestCase`` instance.
    :param unicode control_address: The address of the control service.
    :param int control_port: The port number of the control service.
    :param unicode name: The ZFS pool name.  If ``None``, a random one will be
        generated that identifies the given test.
    """
    if name is None:
        name = random_name(test)
    ca_set, _ = get_credential_sets()
    scratch_directory = FilePath(test.mktemp())
    scratch_directory.makedirs()
    test.config = scratch_directory.child('dataset-config.yml')
    test.config.setContent(
        yaml.safe_dump({
            u"control-service": {
                u"hostname": control_address,
                u"port": control_port,
            },
            u"dataset": {
                u"backend": u"zfs",
                u"name": name,
                # XXX Can't put FilePath in a yaml file (well you can but
                # .... :/)
                u"mount_root": scratch_directory.child(b"mount_root").path,
                u"volume_config_path": scratch_directory.child(
                    b"volume_config.json"
                ).path,
            },
            u"version": 1,
        }))
    ca_set.copy_to(scratch_directory, node=True)
    test.ca_set = ca_set
    test.non_existent_file = scratch_directory.child('missing-config.yml')

deployer = object()


# This should have an explicit interface:
# https://clusterhq.atlassian.net/browse/FLOC-1929
def deployer_factory_stub(**kw):
    if set(kw.keys()) != {"node_uuid", "cluster_uuid", "hostname"}:
        raise TypeError("wrong arguments")
    return deployer


class DummyAgentService(PRecord):
    reactor = field()
    loop_service = field()
    configuration = field()

    @classmethod
    def for_loop_service(cls, loop_service):
        return lambda configuration: cls(
            loop_service=loop_service,
            configuration=configuration,
        )

    def get_api(self):
        return None

    def get_deployer(self, api):
        return None

    def get_loop_service(self, deployer):
        return self.loop_service


class DatasetServiceFactoryTests(SynchronousTestCase):
    """
    Tests for ``DatasetServiceFactory`` using ZFS configuration.
    """
    def setUp(self):
        setup_config(self)

    def test_config_validated(self):
        """
        ``DatasetServiceFactory.get_service`` validates the configuration file.
        """
        self.config.setContent(b"INVALID")

        options = DatasetAgentOptions()
        options.parseOptions([b"--agent-config", self.config.path])

        self.assertRaises(
            ValidationError,
            DatasetServiceFactory().get_service, MemoryCoreReactor(), options,
        )

    def test_missing_configuration_file(self):
        """
        ``DatasetServiceFactory.get_service`` raises an ``IOError`` if the
        given configuration file does not exist.
        """
        options = DatasetAgentOptions()
        options.parseOptions([b"--agent-config", self.non_existent_file.path])

        self.assertRaises(
            IOError,
            DatasetServiceFactory().get_service, MemoryCoreReactor(), options,
        )


def agent_service_setup(test):
    """
    Do some setup common to all of the ``AgentService`` test cases.
    """
    test.ca_set, _ = get_credential_sets()

    test.host = b"192.0.2.5"
    test.port = 54123
    test.reactor = MemoryCoreReactor()

    test.agent_service = AgentService(
        reactor=test.reactor,

        control_service_host=test.host,
        control_service_port=test.port,
        node_credential=test.ca_set.node,
        ca_certificate=test.ca_set.root.credential.certificate,

        backend_name=u"anything",
        api_args={},
    )


class AgentServiceFromConfigurationTests(SynchronousTestCase):
    """
    Tests for ``AgentService.from_configuration``
    """
    def test_initialized(self):
        """
        ``AgentService.from_configuration`` returns an ``AgentService``
        instance with all of its fields initialized from parts of the
        configuration passed in.
        """
        host = b"192.0.2.13"
        port = 2314
        name = u"from_config-test"

        setup_config(self, control_address=host, control_port=port, name=name)
        options = DatasetAgentOptions()
        options.parseOptions([b"--agent-config", self.config.path])
        config = get_configuration(options)
{'fraction_non_alphanumeric': 0.0982094897045658, 'fraction_numerical': 0.006445837063563115, 'mean_word_length': 2.8035410282601294, 'pattern_counts': {'":': 18, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 6, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2624994', 'n_tokens_mistral': 3220, 'n_tokens_neox': 3085, 'n_words': 731}