# (C) Datadog, Inc. 2010-2017
# All rights reserved
# Licensed under Simplified BSD License (see LICENSE)
from __future__ import unicode_literals

import time
from datetime import datetime

import mock
import pytest
from mock import MagicMock
from pyVmomi import vim

from datadog_checks.vsphere import VSphereCheck
from datadog_checks.vsphere.cache_config import CacheConfig
from datadog_checks.vsphere.common import SOURCE_TYPE
from datadog_checks.vsphere.errors import BadConfigError, ConnectionError
from datadog_checks.vsphere.vsphere import (
    REFRESH_METRICS_METADATA_INTERVAL,
    REFRESH_MORLIST_INTERVAL,
    RESOURCE_TYPE_METRICS,
    SHORT_ROLLUP,
)

from .utils import MockedMOR, assertMOR, disable_thread_pool, get_mocked_server

SERVICE_CHECK_TAGS = ["vcenter_server:vsphere_mock", "vcenter_host:None", "foo:bar"]


def test__init__(instance):
    with pytest.raises(BadConfigError):
        # Must define a unique 'name' per vCenter instance
        VSphereCheck('vsphere', {}, {}, [{'': ''}])

    init_config = {
        'clean_morlist_interval': 50,
        'refresh_morlist_interval': 42,
        'refresh_metrics_metadata_interval': -42,
        'batch_property_collector_size': -1,
    }
    check = VSphereCheck('vsphere', init_config, {}, [instance])
    i_key = check._instance_key(instance)

    assert check.time_started > 0
    assert not check.server_instances
    assert check.cache_config.get_interval(CacheConfig.Morlist, i_key) == 42
    assert check.cache_config.get_interval(CacheConfig.Metadata, i_key) == -42
    assert check.clean_morlist_interval == 50
    assert len(check.event_config) == 1
    assert 'vsphere_mock' in check.event_config
    assert not check.registry
    assert not check.latest_event_query
    assert check.batch_collector_size == 0
    assert check.batch_morlist_size == 50
    assert check.excluded_host_tags == []


def test_excluded_host_tags(vsphere, instance, aggregator):
    # Check default value and precedence of instance config over init config
    check = VSphereCheck('vsphere', {}, {}, [instance])
    assert check.excluded_host_tags == []
    check = VSphereCheck('vsphere', {"excluded_host_tags": ["vsphere_host"]}, {}, [instance])
    assert check.excluded_host_tags == ["vsphere_host"]
    instance["excluded_host_tags"] = []
    check = VSphereCheck('vsphere', {"excluded_host_tags": ["vsphere_host"]}, {}, [instance])
    assert check.excluded_host_tags == []

    # Test host tags are excluded from external host metadata, but still stored in the cache for metrics
    vsphere.excluded_host_tags = ["vsphere_host"]
    mocked_vm = MockedMOR(spec="VirtualMachine")
    mocked_host = MockedMOR(spec="HostSystem")
    mocked_mors_attrs = {
        mocked_vm: {
            "name": "mocked_vm",
            "parent": mocked_host,
            "runtime.powerState": vim.VirtualMachinePowerState.poweredOn,
        },
        mocked_host: {"name": "mocked_host", "parent": None},
    }

    with mock.patch("datadog_checks.vsphere.VSphereCheck._collect_mors_and_attributes", return_value=mocked_mors_attrs):

        server_instance = vsphere._get_server_instance(instance)
        result = MagicMock()
        result.value = [23.4]
        server_instance.content.perfManager.QueryPerf.return_value = [MagicMock(value=[result], entity=mocked_vm)]
        vsphere.metadata_cache = MagicMock()
        vsphere.metadata_cache.get_metadata.return_value = {"name": "mymetric", "unit": "kb"}
        vsphere.in_compatibility_mode = MagicMock()
        vsphere.in_compatibility_mode.return_value = False

        vsphere.check(instance)
        ext_host_tags = vsphere.get_external_host_tags()

        # vsphere_host tag not in external metadata
        for host, source_tags in ext_host_tags:
            if host == u"mocked_vm":
                tags = source_tags["vsphere"]
                for tag in tags:
                    assert "vsphere_host:" not in tag
                break

        # vsphere_host tag still in cache for sending with metrics
        aggregator.assert_metric('vsphere.mymetric', value=23.4, hostname="mocked_vm", count=1)
        aggregator.assert_metric_has_tag('vsphere.mymetric', tag="vsphere_host:mocked_host", count=1)


def test__is_excluded():
    """
     * Exclude hosts/vms not compliant with the user's `*_include` configuration.
     * Exclude "non-labeled" virtual machines when the user configuration instructs to.
    """
    # Sample(s)
    include_regexes = {'host_include': "f[o]+", 'vm_include': "f[o]+"}

    # OK
    included_host = MockedMOR(spec="HostSystem", name="foo")
    included_vm = MockedMOR(spec="VirtualMachine", name="foo")

    assert not VSphereCheck._is_excluded(included_host, {"name": included_host.name}, include_regexes, None)
    assert not VSphereCheck._is_excluded(included_vm, {"name": included_vm.name}, include_regexes, None)

    # Not OK!
    excluded_host = MockedMOR(spec="HostSystem", name="bar")
    excluded_vm = MockedMOR(spec="VirtualMachine", name="bar")

    assert VSphereCheck._is_excluded(excluded_host, {"name": excluded_host.name}, include_regexes, None)
    assert VSphereCheck._is_excluded(excluded_vm, {"name": excluded_vm.name}, include_regexes, None)

    # Sample(s)
    include_regexes = None
    include_only_marked = True

    # OK
    included_vm = MockedMOR(spec="VirtualMachine", name="foo", label=True)
    assert not VSphereCheck._is_excluded(
        included_vm, {"customValue": included_vm.customValue}, include_regexes, include_only_marked
    )

    # Not OK
    included_vm = MockedMOR(spec="VirtualMachine", name="foo")
    assert VSphereCheck._is_excluded(included_vm, {"customValue": []}, include_regexes, include_only_marked)


def test_vms_in_filtered_host_are_filtered(vsphere, instance):
    """Test that all vms belonging to a filtered host are also filtered"""
    server_instance = vsphere._get_server_instance(instance)
    filtered_host = MockedMOR(spec="HostSystem")
    filtered_vm = MockedMOR(spec="VirtualMachine")
    non_filtered_host = MockedMOR(spec="HostSystem")
    non_filtered_vm = MockedMOR(spec="VirtualMachine")
    mocked_mors_attrs = {
        filtered_host: {"name": "filtered_host_number_1", "parent": None},
        filtered_vm: {
            "name": "this_vm_is_filtered",
            "runtime.powerState": vim.VirtualMachinePowerState.poweredOn,
            "runtime.host": filtered_host,
        },
        non_filtered_host: {"name": "non_filtered_host_number_1", "parent": None},
        non_filtered_vm: {
            "name": "this_vm_is_not_filtered",
            "runtime.powerState": vim.VirtualMachinePowerState.poweredOn,
            "runtime.host": non_filtered_host,
        },
    }

    regex = {'host_include': '^(?!filtered_.+)'}
    with mock.patch("datadog_checks.vsphere.VSphereCheck._collect_mors_and_attributes", return_value=mocked_mors_attrs):
        obj_list = vsphere._get_all_objs(server_instance, regex, False, [])
        assert len(obj_list[vim.VirtualMachine]) == 1
        assert len(obj_list[vim.HostSystem]) == 1
        assert {
            "mor_type": "vm",
            "mor": non_filtered_vm,
            "hostname": "this_vm_is_not_filtered",
            "tags": ["vsphere_host:non_filtered_host_number_1", "vsphere_type:vm"],
        } == obj_list[vim.VirtualMachine][0]
        assert {
            "mor_type": "host",
            "mor": non_filtered_host,
            "hostname": "non_filtered_host_number_1",
            "tags": ["vsphere_type:host"],
        } == obj_list[vim.HostSystem][0]


def test__get_all_objs(vsphere, instance):
    """
    Test that we don't raise KeyError if the property collector failed to collect some attributes
    and that we handle the case were there are missing attributes
    """
    server_instance = vsphere._get_server_instance(instance)

    vm_no_parent = MockedMOR(spec="VirtualMachine")
    vm_no_powerstate = MockedMOR(spec="VirtualMachine")
    vm_host_parent = MockedMOR(spec="VirtualMachine")
    mocked_host = MockedMOR(spec="HostSystem")
    mocked_datastore = MockedMOR(spec="Datastore")
    mocked_datacenter = MockedMOR(spec="Datacenter")
    mocked_cluster = MockedMOR(spec="ClusterComputeResource")
    mocked_mors_attrs = {
        vm_no_parent: {"name": "vm_no_parent", "runtime.powerState": vim.VirtualMachinePowerState.poweredOn},
        vm_no_powerstate: {"name": "vm_no_powerstate"},
        vm_host_parent: {"parent": mocked_host, "runtime.powerState": vim.VirtualMachinePowerState.poweredOn},
        mocked_host: {"name": "mocked_host", "parent": None},
        mocked_datastore: {},
        mocked_cluster: {"name": "cluster"},
        mocked_datacenter: {"parent": MockedMOR(spec="Folder", name="unknown folder"), "name": "datacenter"},
    }
    with mock.patch("datadog_checks.vsphere.VSphereCheck._collect_mors_and_attributes", return_value=mocked_mors_attrs):
        obj_list = vsphere._get_all_objs(server_instance, None, False, [])
        assert len(obj_list[vim.VirtualMachine]) == 2
        assert {
            "mor_type": "vm",
            "mor": vm_no_parent,
            "hostname": "vm_no_parent",
            "tags": ["vsphere_host:unknown", "vsphere_type:vm"],
        } in obj_list[vim.VirtualMachine]
        assert {
            "mor_type": "vm",
            "mor": vm_host_parent,
            "hostname": "unknown",
            "tags": ["vsphere_host:mocked_host", "vsphere_host:unknown", "vsphere_type:vm"],
        } in obj_list[vim.VirtualMachine]
        assert len(obj_list[vim.HostSystem]) == 1
        assert {
            "mor_type": "host",
            "mor": mocked_host,
            "hostname": "mocked_host",
            "tags": ["vsphere_type:host"],
        } in obj_list[vim.HostSystem]
        assert len(obj_list[vim.Datastore]) == 1
        assert {
            "mor_type": "datastore",
            "mor": mocked_datastore,
            "hostname": None,
            "tags": ["vsphere_datastore:unknown", "vsphere_type:datastore"],
        } in obj_list[vim.Datastore]
        assert len(obj_list[vim.Datacenter]) == 1
        assert {
            "mor_type": "datacenter",
            "mor": mocked_datacenter,
            "hostname": None,
            "tags": ["vsphere_folder:unknown", "vsphere_datacenter:datacenter", "vsphere_type:datacenter"],
        } in obj_list[vim.Datacenter]
        assert len(obj_list[vim.ClusterComputeResource]) == 1
        assert {
            "mor_type": "cluster",
            "mor": mocked_cluster,
            "hostname": None,
            "tags": ["vsphere_cluster:cluster", "vsphere_type:cluster"],
        } in obj_list[vim.ClusterComputeResource]


def test__collect_mors_and_attributes(vsphere, instance):
    """
    Test that we check for errors when collecting properties with property collector
    """
    server_instance = vsphere._get_server_instance(instance)
    with mock.patch("datadog_checks.vsphere.vsphere.vmodl"):
        obj = MagicMock(missingSet=None, obj="obj")
        result = MagicMock(token=None, objects=[obj])
        server_instance.content.propertyCollector.RetrievePropertiesEx.return_value = result
        log = MagicMock()
        vsphere.log = log
        mor_attrs = vsphere._collect_mors_and_attributes(server_instance)
        log.error.assert_not_called()
        assert len(mor_attrs) == 1

        obj.missingSet = [MagicMock(path="prop", fault="fault")]
        mor_attrs = vsphere._collect_mors_and_attributes(server_instance)
        log.error.assert_called_once_with('Unable to retrieve property %s for object %s: %s', 'prop', 'obj', 'fault')
        assert len(mor_attrs) == 1


def test__cache_morlist_raw(vsphere, instance):
    """
    Explore the vCenter infrastructure to discover hosts, virtual machines.

    Input topology:
        ```
        rootFolder
            - datacenter1
                - compute_resource1
                    - host1                   # Filtered out
                    - host2
            - folder1
                - datacenter2
                    - compute_resource2
                        - host3
                        - vm1               # Not labeled
                        - vm2               # Filtered out
                        - vm3               # Powered off
                        - vm4
        ```
    """
    # Samples
    with mock.patch('datadog_checks.vsphere.vsphere.vmodl'):
        instance["host_include_only_regex"] = "host[2-9]"
        instance["vm_include_only_regex"] = "vm[^2]"
        instance["include_only_marked"] = True

        # Discover hosts and virtual machines
        vsphere._cache_morlist_raw(instance)

        # Assertions: 1 labeled+monitored VM + 2 hosts + 2 datacenters + 2 clusters + 1 datastore.
        assertMOR(vsphere, instance, count=8)

        # ...on hosts
        assertMOR(vsphere, instance, spec="host", count=2)
        tags = [
            "vcenter_server:vsphere_mock",
            "vsphere_folder:rootFolder",
            "vsphere_datacenter:datacenter1",
            "vsphere_compute:compute_resource1",
            "vsphere_cluster:compute_resource1",
            "vsphere_type:host",
        ]
        assertMOR(vsphere, instance, name="host2", spec="host", tags=tags)
        tags = [
            "vcenter_server:vsphere_mock",
            "vsphere_folder:rootFolder",
            "vsphere_folder:folder1",
            "vsphere_datacenter:datacenter2",
            "vsphere_compute:compute_resource2",
            "vsphere_cluster:compute_resource2",
            "vsphere_type:host",
        ]
        assertMOR(vsphere, instance, name="host3", spec="host", tags=tags)

        # ...on VMs
        assertMOR(vsphere, instance, spec="vm", count=1)
        tags = [
            "vcenter_server:vsphere_mock",
            "vsphere_folder:folder1",
            "vsphere_datacenter:datacenter2",
            "vsphere_compute:compute_resource2",
            "vsphere_cluster:compute_resource2",
            "vsphere_host:host3",
            "vsphere_type:vm",
        ]
        assertMOR(vsphere, instance, name="vm4", spec="vm", subset=True, tags=tags)


def test_use_guest_hostname(vsphere, instance):
    # Default value
    with mock.patch("datadog_checks.vsphere.VSphereCheck._get_all_objs") as mock_get_all_objs, mock.patch(
        "datadog_checks.vsphere.vsphere.vmodl"
    ):
        vsphere._cache_morlist_raw(instance)
        # Default value
        assert not mock_get_all_objs.call_args[1]["use_guest_hostname"]

        # use guest hostname
        instance["use_guest_hostname"] = True
        vsphere._cache_morlist_raw(instance)
        assert mock_get_all_objs.call_args[1]["use_guest_hostname"]

    with mock.patch("datadog_checks.vsphere.vsphere.vmodl"):

        # Discover hosts and virtual machines
        instance["use_guest_hostname"] = True
        vsphere._cache_morlist_raw(instance)
        assertMOR(vsphere, instance, spec="vm", count=3)
        # Fallback on VM name when guest hostname not available
        assertMOR(vsphere, instance, name="vm1", spec="vm", subset=True)
        assertMOR(vsphere, instance, name="vm2_guest", spec="vm", subset=True)
        assertMOR(vsphere, instance, name="vm4_guest", spec="vm", subset=True)


def test__process_mor_objects_queue(vsphere, instance):
    vsphere.log = MagicMock()
    vsphere._process_mor_objects_queue_async = MagicMock()
    vsphere._process_mor_objects_queue(instance)
    # Queue hasn't been initialized
    vsphere.log.debug.assert_called_once_with(
        "Objects queue is not initialized yet for instance %s, skipping processing", vsphere._instance_key(instance)
    )

    vsphere.batch_morlist_size = 1
    i_key = vsphere._instance_key(instance)
    with mock.patch('datadog_checks.vsphere.vsphere.vmodl'):
        vsphere._cache_morlist_raw(instance)
        assert sum(vsphere.mor_objects_queue.size(i_key, res_type) for res_type in RESOURCE_TYPE_METRICS) == 11
        vsphere._process_mor_objects_queue(instance)
        # Object queue should be empty after processing
        assert sum(vsphere.mor_objects_queue.size(i_key, res_type) for res_type in RESOURCE_TYPE_METRICS) == 0
        assert vsphere._process_mor_objects_queue_async.call_count == 0  # realtime only
        for call_args in vsphere._process_mor_objects_queue_async.call_args_list:
            # query_specs parameter should be a list of size 1 since the batch size is 1
            assert len(call_args[0][1]) == 1

        instance["collect_realtime_only"] = False
        vsphere._cache_morlist_raw(instance)
        assert sum(vsphere.mor_objects_queue.size(i_key, res_type) for res_type in RESOURCE_TYPE_METRICS) == 11
        vsphere._process_mor_objects_queue(instance)
        # Object queue should be empty after processing
        assert sum(vsphere.mor_objects_queue.size(i_key, res_type) for res_type in RESOURCE_TYPE_METRICS) == 0
        assert vsphere._process_mor_objects_queue_async.call_count == 5  # 2 datacenters, 2 clusters, 1 datastore


def test_collect_realtime_only(vsphere, instance):
    """
    Test the collect_realtime_only parameter acts as expected
    """
    vsphere._process_mor_objects_queue_async = MagicMock()
    instance["collect_realtime_only"] = False
    with mock.patch('datadog_checks.vsphere.vsphere.vmodl'):
        vsphere._cache_morlist_raw(instance)
        vsphere._process_mor_objects_queue(instance)
        # Called once to process the 2 datacenters, then 2 clusters, then the datastore
        assert vsphere._process_mor_objects_queue_async.call_count == 3

    instance["collect_realtime_only"] = True
    vsphere._process_mor_objects_queue_async.reset_mock()
    with mock.patch('datadog_checks.vsphere.vsphere.vmodl'):
        vsphere._cache_morlist_raw(instance)
        vsphere._process_mor_objects_queue(instance)
        assert vsphere._process_mor_objects_queue_async.call_count == 0


def test__cache_metrics_metadata(vsphere, instance):
    vsphere.metadata_cache = MagicMock()
    vsphere._cache_metrics_metadata(instance)

    vsphere.metadata_cache.init_instance.assert_called_once_with(vsphere._instance_key(instance))
    vsphere.metadata_cache.set_metadata.assert_called_once()
    vsphere.metadata_cache.set_metric_ids.assert_called_once()


def test__cache_metrics_metadata_compatibility(vsphere, instance):
    server_instance = vsphere._get_server_instance(instance)
    i_key = vsphere._instance_key(instance)
    counter = MagicMock()
    counter.rollupType = "average"
    counter.key = 1
    vsphere.format_metric_name = MagicMock()

    # New way
    instance["collection_level"] = 3
    server_instance.content.perfManager.QueryPerfCounterByLevel.return_value = [counter]
    vsphere._cache_metrics_metadata(instance)

    server_instance.content.perfManager.QueryPerfCounterByLevel.assert_called_once_with(3)
    assert len(vsphere.metadata_cache._metric_ids[i_key]) == 1
    assert len(vsphere.metadata_cache._metadata[i_key]) == 1
    vsphere.format_metric_name.assert_called_once_with(counter)

    # Compatibility mode
    instance["all_metrics"] = False
    del instance["collection_level"]
    vsphere.format_metric_name.reset_mock()
    server_instance.content.perfManager.perfCounter = [counter]
    vsphere._cache_metrics_metadata(instance)

    assert not vsphere.metadata_cache._metric_ids[i_key]
    assert len(vsphere.metadata_cache._metadata[i_key]) == 1
    vsphere.format_metric_name.assert_called_once_with(counter, compatibility=True)


def test_in_compatibility_mode(vsphere, instance):
    vsphere.log = MagicMock()

    instance["collection_level"] = 2
    assert not vsphere.in_compatibility_mode(instance)

    instance["all_metrics"] = True
    assert not vsphere.in_compatibility_mode(instance)
    vsphere.log.warning.assert_not_called()

    assert not vsphere.in_compatibility_mode(instance, log_warning=True)
    vsphere.log.warning.assert_called_once()

    del instance["collection_level"]
    vsphere.log.reset_mock()
    assert vsphere.in_compatibility_mode(instance)
    vsphere.log.warning.assert_not_called()

    assert vsphere.in_compatibility_mode(instance, log_warning=True)
    vsphere.log.warning.assert_called_once()


def test_format_metric_name(vsphere):
    counter = MagicMock()
    counter.groupInfo.key = "group"
    counter.nameInfo.key = "name"
    counter.rollupType = "rollup"
    assert vsphere.format_metric_name(counter, compatibility=True) == "group.name"

    for rollup, short_rollup in SHORT_ROLLUP.items():
        counter.rollupType = rollup
        assert vsphere.format_metric_name(counter) == "group.name.{}".format(short_rollup)


def test_collect_metrics(vsphere, instance):
    with mock.patch('datadog_checks.vsphere.vsphere.vmodl'):
        vsphere.batch_morlist_size = 1
        vsphere._collect_metrics_async = MagicMock()
        vsphere._cache_metrics_metadata(instance)
        vsphere._cache_morlist_raw(instance)
        vsphere._process_mor_objects_queue(instance)
        vsphere.collect_metrics(instance)
        assert vsphere._collect_metrics_async.call_count == 6  # One for each VM/host, datacenters are not collected
        for call_args in vsphere._collect_metrics_async.call_args_list:
            # query_specs parameter should be a list of size 1 since the batch size is 1
            assert len(call_args[0][1]) == 1


def test__collect_metrics_async_compatibility(vsphere, instance):
    server_instance = vsphere._get_server_instance(instance)
    server_instance.content.perfManager.QueryPerf.return_value = [MagicMock(value=[MagicMock()])]
    vsphere.mor_cache = MagicMock()
    vsphere.metadata_cache = MagicMock()
    vsphere.metadata_cache.get_metadata.return_value = {"name": "unknown"}
    vsphere.in_compatibility_mode = MagicMock()
    vsphere.log = MagicMock()

    vsphere.in_compatibility_mode.return_value = True
    vsphere._collect_metrics_async(instance, [])
    vsphere.log.debug.assert_called_with('Skipping unknown `%s` metric.', 'unknown')

    vsphere.log.reset_mock()
    vsphere.in_compatibility_mode.return_value = False
    vsphere._collect_metrics_async(instance, [])
    vsphere.log.debug.assert_not_called()


def test__collect_metrics_async_hostname(vsphere, instance, aggregator):
    server_instance = vsphere._get_server_instance(instance)
    result = MagicMock()
    result.value = [23.4]

    server_instance.content.perfManager.QueryPerf.return_value = [MagicMock(value=[result])]
    mor = {"hostname": "foo"}
    vsphere.mor_cache = MagicMock()
    vsphere.mor_cache.get_mor.return_value = mor
    vsphere.metadata_cache = MagicMock()
    vsphere.metadata_cache.get_metadata.return_value = {"name": "mymetric", "unit": "kb"}
    vsphere.in_compatibility_mode = MagicMock()
    vsphere.in_compatibility_mode.return_value = False

    vsphere._collect_metrics_async(instance, [])
    aggregator.assert_metric('vsphere.mymetric', value=23.4, hostname="foo")


def test_check(vsphere, instance):
    """
    Test the check() method
    """
    with mock.patch('datadog_checks.vsphere.vsphere.vmodl'):
        with mock.patch.object(vsphere, 'set_external_tags') as set_external_tags:
            vsphere.check(instance)
            set_external_tags.assert_called_once()
            all_the_tags = dict(set_external_tags.call_args[0][0])

            assert all_the_tags['vm4'][SOURCE_TYPE] == [
                'vcenter_server:vsphere_mock',
                'vsphere_folder:rootFolder',
                'vsphere_folder:folder1',
                'vsphere_datacenter:datacenter2',
                'vsphere_cluster:compute_resource2',
                'vsphere_compute:compute_resource2',
                'vsphere_host:host3',
                'vsphere_host:host3',
                'vsphere_type:vm',
            ]
            assert all_the_tags['host1'][SOURCE_TYPE] == [
                'vcenter_server:vsphere_mock',
                'vsphere_folder:rootFolder',
                'vsphere_datacenter:datacenter1',
                'vsphere_cluster:compute_resource1',
                'vsphere_compute:compute_resource1',
                'vsphere_type:host',
            ]
            assert all_the_tags['host3'][SOURCE_TYPE] == [
                'vcenter_server:vsphere_mock',
                'vsphere_folder:rootFolder',
                'vsphere_folder:folder1',
                'vsphere_datacenter:datacenter2',
                'vsphere_cluster:compute_resource2',
                'vsphere_compute:compute_resource2',
                'vsphere_type:host',
            ]
            assert all_the_tags['vm2'][SOURCE_TYPE] == [
                'vcenter_server:vsphere_mock',
                'vsphere_folder:rootFolder',
                'vsphere_folder:folder1',
                'vsphere_datacenter:datacenter2',
                'vsphere_cluster:compute_resource2',
                'vsphere_compute:compute_resource2',
                'vsphere_host:host3',
                'vsphere_host:host3',
                'vsphere_type:vm',
            ]
            assert all_the_tags['vm1'][SOURCE_TYPE] == [
                'vcenter_server:vsphere_mock',
                'vsphere_folder:rootFolder',
                'vsphere_folder:folder1',
                'vsphere_datacenter:datacenter2',
                'vsphere_cluster:compute_resource2',
                'vsphere_compute:compute_resource2',
                'vsphere_host:host3',
                'vsphere_host:host3',
                'vsphere_type:vm',
            ]
            assert all_the_tags['host2'][SOURCE_TYPE] == [
                'vcenter_server:vsphere_mock',
                'vsphere_folder:rootFolder',
                'vsphere_datacenter:datacenter1',
                'vsphere_cluster:compute_resource1',
                'vsphere_compute:compute_resource1',
                'vsphere_type:host',
            ]


def test_service_check_ko(aggregator, instance):
    check = disable_thread_pool(VSphereCheck('disk', {}, {}, [instance]))

    with mock.patch('datadog_checks.vsphere.vsphere.connect.SmartConnect') as SmartConnect:
        # SmartConnect fails
        SmartConnect.side_effect = Exception()

        with pytest.raises(ConnectionError):
            check.check(instance)

        aggregator.assert_service_check(
            VSphereCheck.SERVICE_CHECK_NAME, status=VSphereCheck.CRITICAL, count=1, tags=SERVICE_CHECK_TAGS
        )

        aggregator.reset()

        # SmartConnect succeeds, CurrentTime fails
        server = MagicMock()
        server.CurrentTime.side_effect = Exception()
        SmartConnect.side_effect = None
        SmartConnect.return_value = server

        with pytest.raises(ConnectionError):
            check.check(instance)

        aggregator.assert_service_check(
            VSphereCheck.SERVICE_CHECK_NAME, status=VSphereCheck.CRITICAL, count=1, tags=SERVICE_CHECK_TAGS
        )


def test_service_check_ok(aggregator, instance):
    check = disable_thread_pool(VSphereCheck('disk', {}, {}, [instance]))
    with mock.patch('datadog_checks.vsphere.vsphere.vmodl'):
        with mock.patch('datadog_checks.vsphere.vsphere.connect.SmartConnect') as SmartConnect:
            SmartConnect.return_value = get_mocked_server()
            check.check(instance)

            aggregator.assert_service_check(
                VSphereCheck.SERVICE_CHECK_NAME, status=VSphereCheck.OK, tags=SERVICE_CHECK_TAGS
            )


def test__instance_key(vsphere, instance):
    assert vsphere._instance_key(instance) == "vsphere_mock"
    del instance['name']
    with pytest.raises(BadConfigError):
        vsphere._instance_key(instance)


def test__should_cache(instance):
    now = time.time()
    # do not use fixtures for the check instance, some params are set at
    # __init__ time and we need to instantiate the check multiple times
    check = VSphereCheck('vsphere', {}, {}, [instance])
    i_key = check._instance_key(instance)

    # first run should always cache
    assert check._should_cache(instance, CacheConfig.Morlist)
    assert check._should_cache(instance, CacheConfig.Metadata)

    # explicitly set cache expiration times, don't use defaults so we also test
    # configuration is properly propagated
    init_config = {
        'refresh_morlist_interval': 2 * REFRESH_MORLIST_INTERVAL,
        'refresh_metrics_metadata_interval': 2 * REFRESH_METRICS_METADATA_INTERVAL,
    }
    check = VSphereCheck('vsphere', init_config, {}, [instance])
    # simulate previous runs, set the last execution time in the past
    check.cache_config.set_last(CacheConfig.Morlist, i_key, now - (2 * REFRESH_MORLIST_INTERVAL))
    check.cache_config.set_last(CacheConfig.Metadata, i_key, now - (2 * REFRESH_METRICS_METADATA_INTERVAL))

    with mock.patch("time.time", return_value=now):
        assert not check._should_cache(instance, CacheConfig.Morlist)
        assert not check._should_cache(instance, CacheConfig.Metadata)


def alarm_event(from_status='green', to_status='red', message='Some error'):
    now = datetime.utcnow()
    vm = MockedMOR(spec='VirtualMachine')
    dc = MockedMOR(spec="Datacenter")
    dc_arg = vim.event.DatacenterEventArgument(datacenter=dc, name='dc1')
    alarm = MockedMOR(spec="Alarm")
    alarm_arg = vim.event.AlarmEventArgument(alarm=alarm, name='alarm1')
    entity = vim.event.ManagedEntityEventArgument(entity=vm, name='vm1')
    event = vim.event.AlarmStatusChangedEvent(
        entity=entity, fullFormattedMessage=message, createdTime=now, to=to_status, datacenter=dc_arg, alarm=alarm_arg
    )
    setattr(event, 'from', from_status)  # noqa: B009
    return event


def migrated_event():
    now = datetime.utcnow()
    vm = MockedMOR(spec='VirtualMachine', name='vm1')
    vm_arg = vim.event.VmEventArgument(vm=vm)
    host = MockedMOR(spec='HostSystem')
    host_arg = vim.event.HostEventArgument(host=host, name='host1')
    host_dest = MockedMOR(spec='HostSystem')
    host_dest_arg = vim.event.HostEventArgument(host=host_dest, name='host2')
    dc = MockedMOR(spec='Datacenter')
    dc_arg = vim.event.DatacenterEventArgument(datacenter=dc, name='dc1')
    dc_dest = MockedMOR(spec='Datacenter')
    dc_dest_arg = vim.event.DatacenterEventArgument(datacenter=dc_dest, name='dc2')
    ds = MockedMOR(spec='Datastore')
    ds_arg = vim.event.DatastoreEventArgument(datastore=ds, name='ds1')
    ds_dest = MockedMOR(spec='Datastore')
    ds_dest_arg = vim.event.DatastoreEventArgument(datastore=ds_dest, name='ds2')
    event = vim.event.VmBeingHotMigratedEvent(
        vm=vm_arg,
        userName='John',
        fullFormattedMessage='Some error',
        createdTime=now,
        host=host_arg,
        destHost=host_dest_arg,
        datacenter=dc_arg,
        destDatacenter=dc_dest_arg,
        ds=ds_arg,
        destDatastore=ds_dest_arg,
    )
    return event


def test_events(aggregator, vsphere, instance):
    with mock.patch('datadog_checks.vsphere.vsphere.vmodl'):
        server_instance = vsphere._get_server_instance(instance)
        server_instance.content.eventManager.QueryEvents.return_value = [alarm_event()]
        vsphere.event_config['vsphere_mock'] = {'collect_vcenter_alarms': True}
        vsphere.check(instance)
        aggregator.assert_event(
            "vCenter monitor status changed on this alarm, it was green and it's now red.", tags=['foo:bar']
        )


def test_events_tags(aggregator, vsphere, instance):
    with mock.patch('datadog_checks.vsphere.vsphere.vmodl'):
        server_instance = vsphere._get_server_instance(instance)
        server_instance.content.eventManager.QueryEvents.return_value = [migrated_event()]
        vsphere.event_config['vsphere_mock'] = {'collect_vcenter_alarms': True}
        vsphere.check(instance)
        aggregator.assert_event(
            "John has launched a hot migration of this virtual machine",
            exact_match=False,
            tags=[
                'foo:bar',
                'vsphere_host:host1',
                'vsphere_host:host2',
                'vsphere_datacenter:dc1',
                'vsphere_datacenter:dc2',
            ],
        )

        server_instance = vsphere._get_server_instance(instance)
        server_instance.content.eventManager.QueryEvents.return_value = [alarm_event()]
        vsphere.check(instance)
        aggregator.assert_event(
            "vCenter monitor status changed on this alarm, it was green and it's now red.", tags=['foo:bar']
        )


def test_events_gray_handled(aggregator, vsphere, instance):
    with mock.patch('datadog_checks.vsphere.vsphere.vmodl'):
        server_instance = vsphere._get_server_instance(instance)
        event = alarm_event(from_status='gray', message='Went from Gray to Red')
        server_instance.content.eventManager.QueryEvents.return_value = [event]
        vsphere.event_config['vsphere_mock'] = {'collect_vcenter_alarms': True}
        vsphere.check(instance)
        aggregator.assert_event(
            "vCenter monitor status changed on this alarm, it was gray and it's now red.", tags=['foo:bar']
        )

        event = alarm_event(from_status='yellow', to_status='gray', message='Went from Yellow to Gray')
        server_instance.content.eventManager.QueryEvents.return_value = [event]
        vsphere.check(instance)
        aggregator.assert_event(
            "vCenter monitor status changed on this alarm, it was yellow and it's now gray.",
            tags=['foo:bar'],
            alert_type='info',
        )


def test_events_gray_ignored(aggregator, vsphere, instance):
    with mock.patch('datadog_checks.vsphere.vsphere.vmodl'):
        server_instance = vsphere._get_server_instance(instance)
        event = alarm_event(from_status='gray', to_status='green', message='Went from Gray to Green')
        server_instance.content.eventManager.QueryEvents.return_value = [event]
        vsphere.event_config['vsphere_mock'] = {'collect_vcenter_alarms': True}
        vsphere.check(instance)
        assert not aggregator.events
        event = alarm_event(from_status='green', to_status='gray', message='Went from Green to Gray')
        server_instance.content.eventManager.QueryEvents.return_value = [event]
        vsphere.check(instance)
        assert not aggregator.events

[((41, 12, 41, 64), 'datadog_checks.vsphere.VSphereCheck', 'VSphereCheck', ({(41, 25, 41, 34): '"""vsphere"""', (41, 36, 41, 47): 'init_config', (41, 49, 41, 51): '{}', (41, 53, 41, 63): '[instance]'}, {}), "('vsphere', init_config, {}, [instance])", False, 'from datadog_checks.vsphere import VSphereCheck\n'), ((60, 12, 60, 55), 'datadog_checks.vsphere.VSphereCheck', 'VSphereCheck', ({(60, 25, 60, 34): '"""vsphere"""', (60, 36, 60, 38): '{}', (60, 40, 60, 42): '{}', (60, 44, 60, 54): '[instance]'}, {}), "('vsphere', {}, {}, [instance])", False, 'from datadog_checks.vsphere import VSphereCheck\n'), ((62, 12, 62, 93), 'datadog_checks.vsphere.VSphereCheck', 'VSphereCheck', ({(62, 25, 62, 34): '"""vsphere"""', (62, 36, 62, 76): "{'excluded_host_tags': ['vsphere_host']}", (62, 78, 62, 80): '{}', (62, 82, 62, 92): '[instance]'}, {}), "('vsphere', {'excluded_host_tags': ['vsphere_host']}, {}, [\n    instance])", False, 'from datadog_checks.vsphere import VSphereCheck\n'), ((65, 12, 65, 93), 'datadog_checks.vsphere.VSphereCheck', 'VSphereCheck', ({(65, 25, 65, 34): '"""vsphere"""', (65, 36, 65, 76): "{'excluded_host_tags': ['vsphere_host']}", (65, 78, 65, 80): '{}', (65, 82, 65, 92): '[instance]'}, {}), "('vsphere', {'excluded_host_tags': ['vsphere_host']}, {}, [\n    instance])", False, 'from datadog_checks.vsphere import VSphereCheck\n'), ((127, 11, 127, 104), 'datadog_checks.vsphere.VSphereCheck._is_excluded', 'VSphereCheck._is_excluded', ({(127, 37, 127, 50): 'excluded_host', (127, 52, 127, 80): "{'name': excluded_host.name}", (127, 82, 127, 97): 'include_regexes', (127, 99, 127, 103): 'None'}, {}), "(excluded_host, {'name': excluded_host.name},\n    include_regexes, None)", False, 'from datadog_checks.vsphere import VSphereCheck\n'), ((128, 11, 128, 100), 'datadog_checks.vsphere.VSphereCheck._is_excluded', 'VSphereCheck._is_excluded', ({(128, 37, 128, 48): 'excluded_vm', (128, 50, 128, 76): "{'name': excluded_vm.name}", (128, 78, 128, 93): 'include_regexes', (128, 95, 128, 99): 'None'}, {}), "(excluded_vm, {'name': excluded_vm.name},\n    include_regexes, None)", False, 'from datadog_checks.vsphere import VSphereCheck\n'), ((142, 11, 142, 108), 'datadog_checks.vsphere.VSphereCheck._is_excluded', 'VSphereCheck._is_excluded', ({(142, 37, 142, 48): 'included_vm', (142, 50, 142, 69): "{'customValue': []}", (142, 71, 142, 86): 'include_regexes', (142, 88, 142, 107): 'include_only_marked'}, {}), "(included_vm, {'customValue': []}, include_regexes,\n    include_only_marked)", False, 'from datadog_checks.vsphere import VSphereCheck\n'), ((371, 18, 371, 29), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((372, 47, 372, 58), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((405, 47, 405, 58), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((422, 29, 422, 40), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((433, 14, 433, 25), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((436, 33, 436, 44), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((461, 18, 461, 29), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((483, 14, 483, 25), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((489, 32, 489, 52), 'datadog_checks.vsphere.vsphere.SHORT_ROLLUP.items', 'SHORT_ROLLUP.items', ({}, {}), '()', False, 'from datadog_checks.vsphere.vsphere import REFRESH_METRICS_METADATA_INTERVAL, REFRESH_MORLIST_INTERVAL, RESOURCE_TYPE_METRICS, SHORT_ROLLUP\n'), ((511, 24, 511, 35), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((512, 29, 512, 40), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((514, 36, 514, 47), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((515, 18, 515, 29), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((529, 13, 529, 24), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((534, 24, 534, 35), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((536, 29, 536, 40), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((538, 36, 538, 47), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((665, 10, 665, 21), 'time.time', 'time.time', ({}, {}), '()', False, 'import time\n'), ((668, 12, 668, 55), 'datadog_checks.vsphere.VSphereCheck', 'VSphereCheck', ({(668, 25, 668, 34): '"""vsphere"""', (668, 36, 668, 38): '{}', (668, 40, 668, 42): '{}', (668, 44, 668, 54): '[instance]'}, {}), "('vsphere', {}, {}, [instance])", False, 'from datadog_checks.vsphere import VSphereCheck\n'), ((681, 12, 681, 64), 'datadog_checks.vsphere.VSphereCheck', 'VSphereCheck', ({(681, 25, 681, 34): '"""vsphere"""', (681, 36, 681, 47): 'init_config', (681, 49, 681, 51): '{}', (681, 53, 681, 63): '[instance]'}, {}), "('vsphere', init_config, {}, [instance])", False, 'from datadog_checks.vsphere import VSphereCheck\n'), ((692, 10, 692, 27), 'datetime.datetime.utcnow', 'datetime.utcnow', ({}, {}), '()', False, 'from datetime import datetime\n'), ((695, 13, 695, 73), 'pyVmomi.vim.event.DatacenterEventArgument', 'vim.event.DatacenterEventArgument', (), '', False, 'from pyVmomi import vim\n'), ((697, 16, 697, 72), 'pyVmomi.vim.event.AlarmEventArgument', 'vim.event.AlarmEventArgument', (), '', False, 'from pyVmomi import vim\n'), ((698, 13, 698, 72), 'pyVmomi.vim.event.ManagedEntityEventArgument', 'vim.event.ManagedEntityEventArgument', (), '', False, 'from pyVmomi import vim\n'), ((699, 12, 701, 5), 'pyVmomi.vim.event.AlarmStatusChangedEvent', 'vim.event.AlarmStatusChangedEvent', (), '', False, 'from pyVmomi import vim\n'), ((707, 10, 707, 27), 'datetime.datetime.utcnow', 'datetime.utcnow', ({}, {}), '()', False, 'from datetime import datetime\n'), ((709, 13, 709, 45), 'pyVmomi.vim.event.VmEventArgument', 'vim.event.VmEventArgument', (), '', False, 'from pyVmomi import vim\n'), ((711, 15, 711, 67), 'pyVmomi.vim.event.HostEventArgument', 'vim.event.HostEventArgument', (), '', False, 'from pyVmomi import vim\n'), ((713, 20, 713, 77), 'pyVmomi.vim.event.HostEventArgument', 'vim.event.HostEventArgument', (), '', False, 'from pyVmomi import vim\n'), ((715, 13, 715, 73), 'pyVmomi.vim.event.DatacenterEventArgument', 'vim.event.DatacenterEventArgument', (), '', False, 'from pyVmomi import vim\n'), ((717, 18, 717, 83), 'pyVmomi.vim.event.DatacenterEventArgument', 'vim.event.DatacenterEventArgument', (), '', False, 'from pyVmomi import vim\n'), ((719, 13, 719, 71), 'pyVmomi.vim.event.DatastoreEventArgument', 'vim.event.DatastoreEventArgument', (), '', False, 'from pyVmomi import vim\n'), ((721, 18, 721, 81), 'pyVmomi.vim.event.DatastoreEventArgument', 'vim.event.DatastoreEventArgument', (), '', False, 'from pyVmomi import vim\n'), ((722, 12, 733, 5), 'pyVmomi.vim.event.VmBeingHotMigratedEvent', 'vim.event.VmBeingHotMigratedEvent', (), '', False, 'from pyVmomi import vim\n'), ((31, 9, 31, 38), 'pytest.raises', 'pytest.raises', ({(31, 23, 31, 37): 'BadConfigError'}, {}), '(BadConfigError)', False, 'import pytest\n'), ((33, 8, 33, 51), 'datadog_checks.vsphere.VSphereCheck', 'VSphereCheck', ({(33, 21, 33, 30): '"""vsphere"""', (33, 32, 33, 34): '{}', (33, 36, 33, 38): '{}', (33, 40, 33, 50): "[{'': ''}]"}, {}), "('vsphere', {}, {}, [{'': ''}])", False, 'from datadog_checks.vsphere import VSphereCheck\n'), ((81, 9, 81, 119), 'mock.patch', 'mock.patch', (), '', False, 'import mock\n'), ((84, 17, 84, 28), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((87, 33, 87, 44), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((89, 40, 89, 51), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((120, 15, 120, 108), 'datadog_checks.vsphere.VSphereCheck._is_excluded', 'VSphereCheck._is_excluded', ({(120, 41, 120, 54): 'included_host', (120, 56, 120, 84): "{'name': included_host.name}", (120, 86, 120, 101): 'include_regexes', (120, 103, 120, 107): 'None'}, {}), "(included_host, {'name': included_host.name},\n    include_regexes, None)", False, 'from datadog_checks.vsphere import VSphereCheck\n'), ((121, 15, 121, 104), 'datadog_checks.vsphere.VSphereCheck._is_excluded', 'VSphereCheck._is_excluded', ({(121, 41, 121, 52): 'included_vm', (121, 54, 121, 80): "{'name': included_vm.name}", (121, 82, 121, 97): 'include_regexes', (121, 99, 121, 103): 'None'}, {}), "(included_vm, {'name': included_vm.name},\n    include_regexes, None)", False, 'from datadog_checks.vsphere import VSphereCheck\n'), ((136, 15, 138, 5), 'datadog_checks.vsphere.VSphereCheck._is_excluded', 'VSphereCheck._is_excluded', ({(137, 8, 137, 19): 'included_vm', (137, 21, 137, 61): "{'customValue': included_vm.customValue}", (137, 63, 137, 78): 'include_regexes', (137, 80, 137, 99): 'include_only_marked'}, {}), "(included_vm, {'customValue': included_vm.\n    customValue}, include_regexes, include_only_marked)", False, 'from datadog_checks.vsphere import VSphereCheck\n'), ((168, 9, 168, 119), 'mock.patch', 'mock.patch', (), '', False, 'import mock\n'), ((209, 9, 209, 119), 'mock.patch', 'mock.patch', (), '', False, 'import mock\n'), ((259, 9, 259, 59), 'mock.patch', 'mock.patch', ({(259, 20, 259, 58): '"""datadog_checks.vsphere.vsphere.vmodl"""'}, {}), "('datadog_checks.vsphere.vsphere.vmodl')", False, 'import mock\n'), ((260, 14, 260, 51), 'mock.MagicMock', 'MagicMock', (), '', False, 'from mock import MagicMock\n'), ((261, 17, 261, 53), 'mock.MagicMock', 'MagicMock', (), '', False, 'from mock import MagicMock\n'), ((263, 14, 263, 25), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((297, 9, 297, 59), 'mock.patch', 'mock.patch', ({(297, 20, 297, 58): '"""datadog_checks.vsphere.vsphere.vmodl"""'}, {}), "('datadog_checks.vsphere.vsphere.vmodl')", False, 'import mock\n'), ((346, 9, 346, 72), 'mock.patch', 'mock.patch', ({(346, 20, 346, 71): '"""datadog_checks.vsphere.VSphereCheck._get_all_objs"""'}, {}), "('datadog_checks.vsphere.VSphereCheck._get_all_objs')", False, 'import mock\n'), ((346, 95, 348, 5), 'mock.patch', 'mock.patch', ({(347, 8, 347, 46): '"""datadog_checks.vsphere.vsphere.vmodl"""'}, {}), "('datadog_checks.vsphere.vsphere.vmodl')", False, 'import mock\n'), ((358, 9, 358, 59), 'mock.patch', 'mock.patch', ({(358, 20, 358, 58): '"""datadog_checks.vsphere.vsphere.vmodl"""'}, {}), "('datadog_checks.vsphere.vsphere.vmodl')", False, 'import mock\n'), ((381, 9, 381, 59), 'mock.patch', 'mock.patch', ({(381, 20, 381, 58): '"""datadog_checks.vsphere.vsphere.vmodl"""'}, {}), "('datadog_checks.vsphere.vsphere.vmodl')", False, 'import mock\n'), ((407, 9, 407, 59), 'mock.patch', 'mock.patch', ({(407, 20, 407, 58): '"""datadog_checks.vsphere.vsphere.vmodl"""'}, {}), "('datadog_checks.vsphere.vsphere.vmodl')", False, 'import mock\n'), ((415, 9, 415, 59), 'mock.patch', 'mock.patch', ({(415, 20, 415, 58): '"""datadog_checks.vsphere.vsphere.vmodl"""'}, {}), "('datadog_checks.vsphere.vsphere.vmodl')", False, 'import mock\n'), ((495, 9, 495, 59), 'mock.patch', 'mock.patch', ({(495, 20, 495, 58): '"""datadog_checks.vsphere.vsphere.vmodl"""'}, {}), "('datadog_checks.vsphere.vsphere.vmodl')", False, 'import mock\n'), ((497, 41, 497, 52), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((532, 66, 532, 91), 'mock.MagicMock', 'MagicMock', (), '', False, 'from mock import MagicMock\n'), ((549, 9, 549, 59), 'mock.patch', 'mock.patch', ({(549, 20, 549, 58): '"""datadog_checks.vsphere.vsphere.vmodl"""'}, {}), "('datadog_checks.vsphere.vsphere.vmodl')", False, 'import mock\n'), ((616, 32, 616, 72), 'datadog_checks.vsphere.VSphereCheck', 'VSphereCheck', ({(616, 45, 616, 51): '"""disk"""', (616, 53, 616, 55): '{}', (616, 57, 616, 59): '{}', (616, 61, 616, 71): '[instance]'}, {}), "('disk', {}, {}, [instance])", False, 'from datadog_checks.vsphere import VSphereCheck\n'), ((618, 9, 618, 74), 'mock.patch', 'mock.patch', ({(618, 20, 618, 73): '"""datadog_checks.vsphere.vsphere.connect.SmartConnect"""'}, {}), "('datadog_checks.vsphere.vsphere.connect.SmartConnect')", False, 'import mock\n'), ((632, 17, 632, 28), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n'), ((646, 32, 646, 72), 'datadog_checks.vsphere.VSphereCheck', 'VSphereCheck', ({(646, 45, 646, 51): '"""disk"""', (646, 53, 646, 55): '{}', (646, 57, 646, 59): '{}', (646, 61, 646, 71): '[instance]'}, {}), "('disk', {}, {}, [instance])", False, 'from datadog_checks.vsphere import VSphereCheck\n'), ((647, 9, 647, 59), 'mock.patch', 'mock.patch', ({(647, 20, 647, 58): '"""datadog_checks.vsphere.vsphere.vmodl"""'}, {}), "('datadog_checks.vsphere.vsphere.vmodl')", False, 'import mock\n'), ((660, 9, 660, 38), 'pytest.raises', 'pytest.raises', ({(660, 23, 660, 37): 'BadConfigError'}, {}), '(BadConfigError)', False, 'import pytest\n'), ((686, 9, 686, 50), 'mock.patch', 'mock.patch', (), '', False, 'import mock\n'), ((738, 9, 738, 59), 'mock.patch', 'mock.patch', ({(738, 20, 738, 58): '"""datadog_checks.vsphere.vsphere.vmodl"""'}, {}), "('datadog_checks.vsphere.vsphere.vmodl')", False, 'import mock\n'), ((749, 9, 749, 59), 'mock.patch', 'mock.patch', ({(749, 20, 749, 58): '"""datadog_checks.vsphere.vsphere.vmodl"""'}, {}), "('datadog_checks.vsphere.vsphere.vmodl')", False, 'import mock\n'), ((775, 9, 775, 59), 'mock.patch', 'mock.patch', ({(775, 20, 775, 58): '"""datadog_checks.vsphere.vsphere.vmodl"""'}, {}), "('datadog_checks.vsphere.vsphere.vmodl')", False, 'import mock\n'), ((796, 9, 796, 59), 'mock.patch', 'mock.patch', ({(796, 20, 796, 58): '"""datadog_checks.vsphere.vsphere.vmodl"""'}, {}), "('datadog_checks.vsphere.vsphere.vmodl')", False, 'import mock\n'), ((86, 70, 86, 113), 'mock.MagicMock', 'MagicMock', (), '', False, 'from mock import MagicMock\n'), ((269, 26, 269, 63), 'mock.MagicMock', 'MagicMock', (), '', False, 'from mock import MagicMock\n'), ((550, 13, 550, 60), 'mock.patch.object', 'mock.patch.object', ({(550, 31, 550, 38): 'vsphere', (550, 40, 550, 59): '"""set_external_tags"""'}, {}), "(vsphere, 'set_external_tags')", False, 'import mock\n'), ((622, 13, 622, 43), 'pytest.raises', 'pytest.raises', ({(622, 27, 622, 42): 'ConnectionError'}, {}), '(ConnectionError)', False, 'import pytest\n'), ((637, 13, 637, 43), 'pytest.raises', 'pytest.raises', ({(637, 27, 637, 42): 'ConnectionError'}, {}), '(ConnectionError)', False, 'import pytest\n'), ((648, 13, 648, 78), 'mock.patch', 'mock.patch', ({(648, 24, 648, 77): '"""datadog_checks.vsphere.vsphere.connect.SmartConnect"""'}, {}), "('datadog_checks.vsphere.vsphere.connect.SmartConnect')", False, 'import mock\n'), ((510, 83, 510, 94), 'mock.MagicMock', 'MagicMock', ({}, {}), '()', False, 'from mock import MagicMock\n')]