def test_set_clc_credentials_w_creds(self, mock_clc_sdk):
     with patch.dict('os.environ', {
             'CLC_V2_API_USERNAME': '******',
             'CLC_V2_API_PASSWD': 'dummypwd'
     }):
         under_test = ClcNetwork(self.module)
         under_test._set_clc_credentials_from_env()
         mock_clc_sdk.v2.SetCredentials.assert_called_once_with(
             api_username='******', api_passwd='dummypwd')
 def test_set_clc_credentials_from_env(self, mock_clc_sdk):
     with patch.dict('os.environ', {'CLC_V2_API_TOKEN': 'dummyToken',
                                    'CLC_ACCT_ALIAS': 'TEST'}):
         self.module.fail_json.called = False
         under_test = ClcNetwork(self.module)
         under_test._set_clc_credentials_from_env()
     self.assertEqual(under_test.clc._LOGIN_TOKEN_V2, 'dummyToken')
     self.assertFalse(mock_clc_sdk.v2.SetCredentials.called)
     self.assertEqual(self.module.fail_json.called, False)
 def test_set_clc_credentials_from_env(self, mock_clc_sdk):
     with patch.dict('os.environ', {
             'CLC_V2_API_TOKEN': 'dummyToken',
             'CLC_ACCT_ALIAS': 'TEST'
     }):
         self.module.fail_json.called = False
         under_test = ClcNetwork(self.module)
         under_test._set_clc_credentials_from_env()
     self.assertEqual(under_test.clc._LOGIN_TOKEN_V2, 'dummyToken')
     self.assertFalse(mock_clc_sdk.v2.SetCredentials.called)
     self.assertEqual(self.module.fail_json.called, False)
    def setUp(self):

        existing_net = mock.MagicMock()
        existing_net.name = 'existing'
        v2_networks = mock.MagicMock()
        v2_networks.Get = mock.MagicMock(side_effect=lambda key: existing_net
                                         if key == "existing" else None)
        self.mock_nets = v2_networks
        self.existing_net = existing_net

        self.module = FakeAnsibleModule()
        self.network = ClcNetwork(self.module)
        self.network.module.exit_json = mock.MagicMock()
        self.network_dict = {}
        self.network.clc.v2.Network = mock.MagicMock()
        self.network.clc.v2.Networks = mock.MagicMock()
        self.network.clc.v2.API.Call = mock.MagicMock()
 def test_argument_spec_contract(self):
     args = ClcNetwork._define_module_argument_spec()
     self.assertEqual(args, dict(
         id=dict(required=False),
         name=dict(required=False),
         location=dict(required=True),
         description=dict(required=False),
         state=dict(default='present', choices=['present', 'absent']),
         wait=dict(default=True, type='bool')
     ))
 def test_argument_spec_contract(self):
     args = ClcNetwork._define_module_argument_spec()
     self.assertEqual(
         args,
         dict(id=dict(required=False),
              name=dict(required=False),
              location=dict(required=True),
              description=dict(required=False),
              state=dict(default='present', choices=['present', 'absent']),
              wait=dict(default=True, type='bool')))
    def setUp(self):

        existing_net = mock.MagicMock()
        existing_net.name = 'existing'
        v2_networks = mock.MagicMock()
        v2_networks.Get = mock.MagicMock(side_effect=lambda key: existing_net if key=="existing" else None)
        self.mock_nets = v2_networks
        self.existing_net = existing_net

        self.module = FakeAnsibleModule()
        self.network = ClcNetwork(self.module)
        self.network.module.exit_json = mock.MagicMock()
        self.network_dict = {}
        self.network.clc.v2.Network  = mock.MagicMock()
        self.network.clc.v2.Networks = mock.MagicMock()
        self.network.clc.v2.API.Call = mock.MagicMock()
 def test_set_clc_credentials_w_no_creds(self):
     with patch.dict('os.environ', {}, clear=True):
         under_test = ClcNetwork(self.module)
         under_test._set_clc_credentials_from_env()
     self.assertEqual(self.module.fail_json.called, True)
 def test_set_clc_credentials_w_api_url(self, mock_clc_sdk):
     with patch.dict('os.environ', {'CLC_V2_API_URL': 'dummyapiurl'}):
         under_test = ClcNetwork(self.module)
         under_test._set_clc_credentials_from_env()
         self.assertEqual(under_test.clc.defaults.ENDPOINT_URL_V2, 'dummyapiurl')
 def test_set_clc_credentials_w_creds(self, mock_clc_sdk):
     with patch.dict('os.environ', {'CLC_V2_API_USERNAME': '******', 'CLC_V2_API_PASSWD': 'dummypwd'}):
         under_test = ClcNetwork(self.module)
         under_test._set_clc_credentials_from_env()
         mock_clc_sdk.v2.SetCredentials.assert_called_once_with(api_username='******', api_passwd='dummypwd')
    def test_set_user_agent(self, mock_clc_sdk):
        clc_network.__version__ = "1"
        ClcNetwork._set_user_agent(mock_clc_sdk)

        self.assertTrue(mock_clc_sdk.SetRequestsSession.called)
class TestClcNetwork(unittest.TestCase):

    def setUp(self):

        existing_net = mock.MagicMock()
        existing_net.name = 'existing'
        v2_networks = mock.MagicMock()
        v2_networks.Get = mock.MagicMock(side_effect=lambda key: existing_net if key=="existing" else None)
        self.mock_nets = v2_networks
        self.existing_net = existing_net

        self.module = FakeAnsibleModule()
        self.network = ClcNetwork(self.module)
        self.network.module.exit_json = mock.MagicMock()
        self.network_dict = {}
        self.network.clc.v2.Network  = mock.MagicMock()
        self.network.clc.v2.Networks = mock.MagicMock()
        self.network.clc.v2.API.Call = mock.MagicMock()

    # Begin copy/pasta tests

    def test_api_set_credentials(self):
        self.network.clc.v2.SetCredentials = mock.MagicMock()
        with patch.dict('os.environ', {'CLC_V2_API_USERNAME':'******', 'CLC_V2_API_PASSWD':'UsErnaME'}):
            try:
                self.network.process_request()
            except:
                # It'll die, and we don't care
                pass

        self.network.clc.v2.SetCredentials.assert_called_once_with(api_username='******',api_passwd='UsErnaME')

    @patch.object(clc_network, 'clc_sdk')
    def test_set_user_agent(self, mock_clc_sdk):
        clc_network.__version__ = "1"
        ClcNetwork._set_user_agent(mock_clc_sdk)

        self.assertTrue(mock_clc_sdk.SetRequestsSession.called)

    @patch.object(ClcNetwork, 'clc')
    def test_set_clc_credentials_from_env(self, mock_clc_sdk):
        with patch.dict('os.environ', {'CLC_V2_API_TOKEN': 'dummyToken',
                                       'CLC_ACCT_ALIAS': 'TEST'}):
            self.module.fail_json.called = False
            under_test = ClcNetwork(self.module)
            under_test._set_clc_credentials_from_env()
        self.assertEqual(under_test.clc._LOGIN_TOKEN_V2, 'dummyToken')
        self.assertFalse(mock_clc_sdk.v2.SetCredentials.called)
        self.assertEqual(self.module.fail_json.called, False)

    @patch.object(ClcNetwork, 'clc')
    def test_set_clc_credentials_w_creds(self, mock_clc_sdk):
        with patch.dict('os.environ', {'CLC_V2_API_USERNAME': '******', 'CLC_V2_API_PASSWD': 'dummypwd'}):
            under_test = ClcNetwork(self.module)
            under_test._set_clc_credentials_from_env()
            mock_clc_sdk.v2.SetCredentials.assert_called_once_with(api_username='******', api_passwd='dummypwd')

    @patch.object(ClcNetwork, 'clc')
    def test_set_clc_credentials_w_api_url(self, mock_clc_sdk):
        with patch.dict('os.environ', {'CLC_V2_API_URL': 'dummyapiurl'}):
            under_test = ClcNetwork(self.module)
            under_test._set_clc_credentials_from_env()
            self.assertEqual(under_test.clc.defaults.ENDPOINT_URL_V2, 'dummyapiurl')

    def test_set_clc_credentials_w_no_creds(self):
        with patch.dict('os.environ', {}, clear=True):
            under_test = ClcNetwork(self.module)
            under_test._set_clc_credentials_from_env()
        self.assertEqual(self.module.fail_json.called, True)

    def test_clc_module_not_found(self):
        # Setup Mock Import Function
        import __builtin__ as builtins
        real_import = builtins.__import__
        def mock_import(name, *args):
            if name == 'clc': raise ImportError
            return real_import(name, *args)
        # Under Test
        with mock.patch('__builtin__.__import__', side_effect=mock_import):
            reload(clc_network)
            clc_network.ClcNetwork(self.module)
        # Assert Expected Behavior
        self.module.fail_json.assert_called_with(msg='clc-python-sdk required for this module')
        reload(clc_network)

    def test_requests_invalid_version(self):
        # Setup Mock Import Function
        import __builtin__ as builtins
        real_import = builtins.__import__
        def mock_import(name, *args):
            if name == 'requests':
                args[0]['requests'].__version__ = '2.4.0'
            return real_import(name, *args)
        # Under Test
        with mock.patch('__builtin__.__import__', side_effect=mock_import):
            reload(clc_network)
            clc_network.ClcNetwork(self.module)
        # Assert Expected Behavior
        self.module.fail_json.assert_called_with(msg='requests library  version should be >= 2.5.0')
        reload(clc_network)

    def test_requests_module_not_found(self):
        # Setup Mock Import Function
        import __builtin__ as builtins
        real_import = builtins.__import__
        def mock_import(name, *args):
            if name == 'requests':
                args[0]['requests'].__version__ = '2.7.0'
                raise ImportError
            return real_import(name, *args)
        # Under Test
        with mock.patch('__builtin__.__import__', side_effect=mock_import):
            reload(clc_network)
            clc_network.ClcNetwork(self.module)
        # Assert Expected Behavior
        self.module.fail_json.assert_called_with(msg='requests library is required for this module')
        reload(clc_network)

    @patch.object(clc_network, 'AnsibleModule')
    @patch.object(clc_network, 'ClcNetwork')
    def test_main(self, mock_ClcNetwork, mock_AnsibleModule):
        mock_ClcNetwork_instance        = mock.MagicMock()
        mock_AnsibleModule_instance     = mock.MagicMock()
        mock_ClcNetwork.return_value    = mock_ClcNetwork_instance
        mock_AnsibleModule.return_value = mock_AnsibleModule_instance

        clc_network.main()

        mock_ClcNetwork.assert_called_once_with(mock_AnsibleModule_instance)
        assert mock_ClcNetwork_instance.process_request.call_count ==1


    # End copy/pasta tests


    def test_argument_spec_contract(self):
        args = ClcNetwork._define_module_argument_spec()
        self.assertEqual(args, dict(
            id=dict(required=False),
            name=dict(required=False),
            location=dict(required=True),
            description=dict(required=False),
            state=dict(default='present', choices=['present', 'absent']),
            wait=dict(default=True, type='bool')
        ))

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_populates_network_list(self, mock_set_creds):
        mock_nets = mock.MagicMock()
        self.network.clc.v2.Networks = mock.MagicMock(return_value=mock_nets)
        self.module.params = {
            'id': 'nope',
            'location': 'mock_loc'
        }

        self.network.process_request()

        self.network.clc.v2.Networks.assert_called_once_with(location="mock_loc")
        self.assertEqual(mock_nets, self.network.networks)

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_calls_sdk_network_create(self, mock_set_creds):
        with patch.object(ClcNetwork, '_populate_networks', return_value=self.mock_nets) as mock_nets:
            self.network.clc.v2.Network.Create = mock.MagicMock()
            self.module.params = {
                'location': 'mock_loc'
            }

            self.network.process_request()

            self.network.clc.v2.Network.Create.assert_called_once_with(location="mock_loc")

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_waits_on_request(self, mock_set_creds):
        with patch.object(ClcNetwork, '_populate_networks', return_value=self.mock_nets) as mock_nets:
            mock_request = mock.MagicMock()
            mock_request.WaitUntilComplete = mock.MagicMock(return_value=0)
            self.network.clc.v2.Network.Create = mock.MagicMock(return_value=mock_request)
            self.module.params = {
                'location': 'mock_loc'
            }

            self.network.process_request()

            self.assertEqual(1, mock_request.WaitUntilComplete.call_count)
            self.assertEqual(self.module.fail_json.called, False)

    def ugly_setup(self, mock_update, network_id):
        """
        Long comment time!  This level of setup is most certainly unnecessary, as this
        logic should be handled in the Python SDK.  Unfortunately, since the network API
        remains in the 'experimental' space, it stands to reason that it will be further
        refined/changed, so effort is not being expended enhacing the Requests portion of
        the SDK to handle waiting on and returning network objects post-wait.  As a stop-gap,
        enjoy the mocking shenanigans that follow.
        """

        # Step the first: Mock the status request
        initial_name = 'vlan_bob_192.168.222'
        initial_desc = 'vlan_bob_192.168.222 description'
        status_uri = '/v2-experimental/operations/xxx/status/id'
        network_uri = '/v2-experimental/networks/xxx/dcx/54321'

        mock_request = mock.MagicMock()
        mock_request.uri = status_uri
        status_output = {
            'requestType': 'blueprintOperation',
            'status': 'succeeded',
            'summary': {
                'blueprintId': 12345,
                'locationId': 'DCx',
                'links': [{
                    'href': network_uri,
                    'id': network_id,
                    'rel': 'network'
                }]
            }
        }

        # Step the Second: Mock out the two API calls
        new_network = {
            'name': initial_name,
            'links': [],
            'vlan': 'bob',
            'id': network_id,
            'netmask': '255.255.255.0',
            'cidr': '192.168.222.0/24',
            'type': 'private',
            'gateway': '192.168.222.1',
            'description': initial_desc
        }

        response_map = {
            status_uri: status_output,
            network_uri: new_network
        }

        self.network.clc.v2.API.Call = mock.MagicMock(side_effect=lambda x, uri: response_map[uri] if uri in response_map else 'doing it wrong')

        # Step the Third: Mock the instantiation of a v2 Network object
        mock_network = mock.MagicMock()
        mock_network.id = network_id
        mock_network.name = initial_name
        mock_network.data = new_network
        self.network.clc.v2.Network = mock.MagicMock(return_value=mock_network)

        # Step the Fourth: Mock the wait/create calls
        mock_requests = mock.MagicMock()
        mock_requests.requests = [mock_request]
        mock_requests.WaitUntilComplete = mock.MagicMock(return_value=0)
        self.network.clc.v2.Network.Create = mock.MagicMock(return_value=mock_requests)
        mock_update.return_value = True, mock_network

        return status_uri, network_uri, mock_network

    @patch.object(ClcNetwork, '_update_network')
    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_updates_network_after_create_wait_if_provided_name_or_desc(self, mock_set_creds, mock_update):
        with patch.object(ClcNetwork, '_populate_networks', return_value=self.mock_nets) as mock_nets:
            network_id = 24601
            uri1, uri2, mock_network = self.ugly_setup(mock_update, network_id)
            new_name = "mocketymockmock"
            new_desc = "mockerymockmockdesc"
            self.module.params = {
                'name': new_name,
                'desc': new_desc,
                'location': 'mock_loc'
            }
            self.network.process_request()

            self.assertEqual(2, self.network.clc.v2.API.Call.call_count)
            self.network.clc.v2.API.Call.assert_any_call('GET', uri1)
            self.network.clc.v2.API.Call.assert_called_with('GET', uri2)
            self.network.clc.v2.Network.assert_called_once_with(network_id,network_obj=mock_network.data)
            mock_update.assert_called_once_with(mock_network,self.module.params)

    @patch.object(ClcNetwork, '_update_network')
    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_skips_update_after_create_if_no_name_or_desc_are_provided(self, mock_set_creds, mock_update):
        with patch.object(ClcNetwork, '_populate_networks', return_value=self.mock_nets) as mock_nets:
            network_id = 24601
            uri1, uri2, mock_network = self.ugly_setup(mock_update, network_id)
            new_name = "mocketymockmock"
            new_desc = "mockerymockmockdesc"
            self.module.params = {
                'location': 'mock_loc'
            }
            self.network.process_request()

            self.assertEqual(2, self.network.clc.v2.API.Call.call_count)
            self.network.clc.v2.API.Call.assert_any_call('GET', uri1)
            self.network.clc.v2.API.Call.assert_called_with('GET', uri2)
            self.network.clc.v2.Network.assert_called_once_with(network_id,network_obj=mock_network.data)
            mock_update.assert_not_called()


    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_reports_failure_when_create_fails(self, mock_set_creds):
        with patch.object(ClcNetwork, '_populate_networks', return_value=self.mock_nets) as mock_nets:
            mock_request = mock.MagicMock()
            mock_request.WaitUntilComplete = mock.MagicMock(return_value=1)
            self.network.clc.v2.Network.Create = mock.MagicMock(return_value=mock_request)
            self.module.params = {
                'location': 'mock_loc'
            }

            self.network.process_request()

            self.assertEqual(1, mock_request.WaitUntilComplete.call_count)
            self.module.fail_json.assert_called_once_with(msg="Unable to create network")

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_skips_wait_when_wait_false(self, mock_set_creds):
        with patch.object(ClcNetwork, '_populate_networks', return_value=self.mock_nets) as mock_nets:
            mock_request = mock.MagicMock()
            mock_request.WaitUntilComplete = mock.MagicMock(return_value=0)
            self.network.clc.v2.Network.Create = mock.MagicMock(return_value=mock_request)
            self.module.params = {
                'location': 'mock_loc',
                'wait': False
            }

            self.network.process_request()

            self.assertEqual(0, mock_request.WaitUntilComplete.call_count)

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_calls_update_when_network_exists_and_is_not_current(self, mock_set_creds):
        with patch.object(ClcNetwork, '_populate_networks', return_value=self.mock_nets):
            name = 'ShinyNewName'
            desc = 'ShinyNewDescription'
            self.network.clc.v2.Network.Create = mock.MagicMock()
            self.existing_net.Update = mock.MagicMock()
            self.module.params = {
                'id': 'existing',
                'name': name,
                'description': desc,
                'location': 'mock_loc',
            }

            self.network.process_request()

            self.assertEqual(0, self.network.clc.v2.Network.Create.call_count)
            self.existing_net.Update.assert_called_once_with(name,description=desc,location='mock_loc' )

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_calls_update_with_description_when_name_not_provided(self, mock_set_creds):
        with patch.object(ClcNetwork, '_populate_networks', return_value=self.mock_nets):
            desc = 'ShinyNewDescription'
            self.network.clc.v2.Network.Create = mock.MagicMock()
            self.existing_net.Update = mock.MagicMock()
            self.module.params = {
                'id': 'existing',
                'description': desc,
                'location': 'mock_loc',
            }

            self.network.process_request()

            self.assertEqual(0, self.network.clc.v2.Network.Create.call_count)
            self.existing_net.Update.assert_called_once_with('existing',description=desc,location='mock_loc' )


    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_calls_update_when_network_exists_and_only_name_is_not_current(self, mock_set_creds):
        with patch.object(ClcNetwork, '_populate_networks', return_value=self.mock_nets):
            name = 'ShinyNewName'
            desc = 'ShinyNewDescription'
            self.network.clc.v2.Network.Create = mock.MagicMock()
            self.existing_net.Update = mock.MagicMock()
            self.module.params = {
                'id': 'existing',
                'name': name,
                'location': 'mock_loc',
            }

            self.network.process_request()

            self.assertEqual(0, self.network.clc.v2.Network.Create.call_count)
            self.existing_net.Update.assert_called_once_with(name, location='mock_loc')



    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_creates_and_exits_with_expected_network(self, mock_set_creds):
        with patch.object(ClcNetwork, '_populate_networks', return_value=self.mock_nets):
            mock_new = mock.MagicMock()
            mock_new.id = '12345'
            mock_new.alias = 'my_alias'
            mock_new.data = {
                'id': 'working',
                'field': 'value'
            }
            self.network.clc.v2.Network = mock.MagicMock(return_value=mock_new)

            mock_request = mock.MagicMock()
            mock_request.WaitUntilComplete = mock.MagicMock(return_value=0)
            self.network.clc.v2.Network.Create = mock.MagicMock(return_value=mock_request)
            self.module.params = {
                'id': 'working',
                'location': 'mock_loc'
            }

            self.network.process_request()

            self.module.exit_json.assert_called_once_with(changed=True,network=mock_new.data)

    def update_data(self, payload):
        self.existing_net.data = payload

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_updates_and_exits_with_expected_network(self, mock_set_creds):
        with patch.object(ClcNetwork, '_populate_networks', return_value=self.mock_nets):
            new_name = 'new_name'
            mock_update = self.existing_net
            mock_update.alias = 'my_alias'
            mock_update.data = {
                'id': 'existing',
                'field': 'value'
            }

            expected = mock_update.data
            expected['name'] = new_name

            self.existing_net.Update = mock.MagicMock(side_effect=self.update_data(expected))
            self.module.params = {
                'id': 'existing',
                'name': new_name,
                'location': 'mock_loc'
            }

            self.network.process_request()

            self.module.exit_json.assert_called_once_with(changed=True,network=expected)

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_exits_with_expected_request_when_wait_false(self, mock_set_creds):
        with patch.object(ClcNetwork, '_populate_networks', return_value=self.mock_nets):
            op_id = "operationId"
            op_uri = "/v2-experimental/operations/xxx/status/operationId"
            mock_request = mock.MagicMock()
            mock_request.id = op_id
            mock_request.uri = op_uri
            mock_requests = create_autospec(clc_sdk.v2.Requests)
            mock_requests.requests = [mock_request]
            self.network.clc.v2.Network.Create = mock.MagicMock(return_value=mock_requests)
            self.module.params = {
                'location': 'mock_loc',
                'wait': False
            }

            self.network.process_request()

            expected = {
                "id": op_id,
                "uri": op_uri
            }

            self.module.exit_json.assert_called_once_with(changed=True,network=expected)


    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_for_delete_calls_sdk_delete_and_reports_change(self, mock_set_creds):
        with patch.object(ClcNetwork, '_populate_networks', return_value=self.mock_nets) as mock_nets:
            self.existing_net.Delete = mock.MagicMock()
            self.module.params = {
                'state': 'absent',
                'id': 'existing',
                'location': 'mock_loc'
            }

            self.network.process_request()

            self.existing_net.Delete.assert_called_once_with(location="mock_loc")
            self.module.exit_json.assert_called_once_with(changed=True, network=None)

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_for_delete_returns_no_change_when_network_not_found(self, mock_set_creds):
        with patch.object(ClcNetwork, '_populate_networks', return_value=self.mock_nets) as mock_nets:
            self.existing_net.Delete = mock.MagicMock()
            self.module.params = {
                'state': 'absent',
                'id': 'non-existing',
                'location': 'mock_loc'
            }

            self.network.process_request()

            self.assertEqual(0, self.existing_net.Delete.call_count)
            self.module.exit_json.assert_called_once_with(changed=False, network=None)
    def test_set_user_agent(self, mock_clc_sdk):
        clc_network.__version__ = "1"
        ClcNetwork._set_user_agent(mock_clc_sdk)

        self.assertTrue(mock_clc_sdk.SetRequestsSession.called)
class TestClcNetwork(unittest.TestCase):
    def setUp(self):

        existing_net = mock.MagicMock()
        existing_net.name = 'existing'
        v2_networks = mock.MagicMock()
        v2_networks.Get = mock.MagicMock(side_effect=lambda key: existing_net
                                         if key == "existing" else None)
        self.mock_nets = v2_networks
        self.existing_net = existing_net

        self.module = FakeAnsibleModule()
        self.network = ClcNetwork(self.module)
        self.network.module.exit_json = mock.MagicMock()
        self.network_dict = {}
        self.network.clc.v2.Network = mock.MagicMock()
        self.network.clc.v2.Networks = mock.MagicMock()
        self.network.clc.v2.API.Call = mock.MagicMock()

    # Begin copy/pasta tests

    def test_api_set_credentials(self):
        self.network.clc.v2.SetCredentials = mock.MagicMock()
        with patch.dict('os.environ', {
                'CLC_V2_API_USERNAME': '******',
                'CLC_V2_API_PASSWD': 'UsErnaME'
        }):
            try:
                self.network.process_request()
            except:
                # It'll die, and we don't care
                pass

        self.network.clc.v2.SetCredentials.assert_called_once_with(
            api_username='******', api_passwd='UsErnaME')

    @patch.object(clc_network, 'clc_sdk')
    def test_set_user_agent(self, mock_clc_sdk):
        clc_network.__version__ = "1"
        ClcNetwork._set_user_agent(mock_clc_sdk)

        self.assertTrue(mock_clc_sdk.SetRequestsSession.called)

    @patch.object(ClcNetwork, 'clc')
    def test_set_clc_credentials_from_env(self, mock_clc_sdk):
        with patch.dict('os.environ', {
                'CLC_V2_API_TOKEN': 'dummyToken',
                'CLC_ACCT_ALIAS': 'TEST'
        }):
            self.module.fail_json.called = False
            under_test = ClcNetwork(self.module)
            under_test._set_clc_credentials_from_env()
        self.assertEqual(under_test.clc._LOGIN_TOKEN_V2, 'dummyToken')
        self.assertFalse(mock_clc_sdk.v2.SetCredentials.called)
        self.assertEqual(self.module.fail_json.called, False)

    @patch.object(ClcNetwork, 'clc')
    def test_set_clc_credentials_w_creds(self, mock_clc_sdk):
        with patch.dict('os.environ', {
                'CLC_V2_API_USERNAME': '******',
                'CLC_V2_API_PASSWD': 'dummypwd'
        }):
            under_test = ClcNetwork(self.module)
            under_test._set_clc_credentials_from_env()
            mock_clc_sdk.v2.SetCredentials.assert_called_once_with(
                api_username='******', api_passwd='dummypwd')

    @patch.object(ClcNetwork, 'clc')
    def test_set_clc_credentials_w_api_url(self, mock_clc_sdk):
        with patch.dict('os.environ', {'CLC_V2_API_URL': 'dummyapiurl'}):
            under_test = ClcNetwork(self.module)
            under_test._set_clc_credentials_from_env()
            self.assertEqual(under_test.clc.defaults.ENDPOINT_URL_V2,
                             'dummyapiurl')

    def test_set_clc_credentials_w_no_creds(self):
        with patch.dict('os.environ', {}, clear=True):
            under_test = ClcNetwork(self.module)
            under_test._set_clc_credentials_from_env()
        self.assertEqual(self.module.fail_json.called, True)

    def test_clc_module_not_found(self):
        # Setup Mock Import Function
        import __builtin__ as builtins
        real_import = builtins.__import__

        def mock_import(name, *args):
            if name == 'clc': raise ImportError
            return real_import(name, *args)

        # Under Test
        with mock.patch('__builtin__.__import__', side_effect=mock_import):
            reload(clc_network)
            clc_network.ClcNetwork(self.module)
        # Assert Expected Behavior
        self.module.fail_json.assert_called_with(
            msg='clc-python-sdk required for this module')
        reload(clc_network)

    def test_requests_invalid_version(self):
        # Setup Mock Import Function
        import __builtin__ as builtins
        real_import = builtins.__import__

        def mock_import(name, *args):
            if name == 'requests':
                args[0]['requests'].__version__ = '2.4.0'
            return real_import(name, *args)

        # Under Test
        with mock.patch('__builtin__.__import__', side_effect=mock_import):
            reload(clc_network)
            clc_network.ClcNetwork(self.module)
        # Assert Expected Behavior
        self.module.fail_json.assert_called_with(
            msg='requests library  version should be >= 2.5.0')
        reload(clc_network)

    def test_requests_module_not_found(self):
        # Setup Mock Import Function
        import __builtin__ as builtins
        real_import = builtins.__import__

        def mock_import(name, *args):
            if name == 'requests':
                args[0]['requests'].__version__ = '2.7.0'
                raise ImportError
            return real_import(name, *args)

        # Under Test
        with mock.patch('__builtin__.__import__', side_effect=mock_import):
            reload(clc_network)
            clc_network.ClcNetwork(self.module)
        # Assert Expected Behavior
        self.module.fail_json.assert_called_with(
            msg='requests library is required for this module')
        reload(clc_network)

    @patch.object(clc_network, 'AnsibleModule')
    @patch.object(clc_network, 'ClcNetwork')
    def test_main(self, mock_ClcNetwork, mock_AnsibleModule):
        mock_ClcNetwork_instance = mock.MagicMock()
        mock_AnsibleModule_instance = mock.MagicMock()
        mock_ClcNetwork.return_value = mock_ClcNetwork_instance
        mock_AnsibleModule.return_value = mock_AnsibleModule_instance

        clc_network.main()

        mock_ClcNetwork.assert_called_once_with(mock_AnsibleModule_instance)
        assert mock_ClcNetwork_instance.process_request.call_count == 1

    # End copy/pasta tests

    def test_argument_spec_contract(self):
        args = ClcNetwork._define_module_argument_spec()
        self.assertEqual(
            args,
            dict(id=dict(required=False),
                 name=dict(required=False),
                 location=dict(required=True),
                 description=dict(required=False),
                 state=dict(default='present', choices=['present', 'absent']),
                 wait=dict(default=True, type='bool')))

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_populates_network_list(self, mock_set_creds):
        mock_nets = mock.MagicMock()
        self.network.clc.v2.Networks = mock.MagicMock(return_value=mock_nets)
        self.module.params = {'id': 'nope', 'location': 'mock_loc'}

        self.network.process_request()

        self.network.clc.v2.Networks.assert_called_once_with(
            location="mock_loc")
        self.assertEqual(mock_nets, self.network.networks)

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_calls_sdk_network_create(
            self, mock_set_creds):
        with patch.object(ClcNetwork,
                          '_populate_networks',
                          return_value=self.mock_nets) as mock_nets:
            self.network.clc.v2.Network.Create = mock.MagicMock()
            self.module.params = {'location': 'mock_loc'}

            self.network.process_request()

            self.network.clc.v2.Network.Create.assert_called_once_with(
                location="mock_loc")

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_waits_on_request(self, mock_set_creds):
        with patch.object(ClcNetwork,
                          '_populate_networks',
                          return_value=self.mock_nets) as mock_nets:
            mock_request = mock.MagicMock()
            mock_request.WaitUntilComplete = mock.MagicMock(return_value=0)
            self.network.clc.v2.Network.Create = mock.MagicMock(
                return_value=mock_request)
            self.module.params = {'location': 'mock_loc'}

            self.network.process_request()

            self.assertEqual(1, mock_request.WaitUntilComplete.call_count)
            self.assertEqual(self.module.fail_json.called, False)

    def ugly_setup(self, mock_update, network_id):
        """
        Long comment time!  This level of setup is most certainly unnecessary, as this
        logic should be handled in the Python SDK.  Unfortunately, since the network API
        remains in the 'experimental' space, it stands to reason that it will be further
        refined/changed, so effort is not being expended enhacing the Requests portion of
        the SDK to handle waiting on and returning network objects post-wait.  As a stop-gap,
        enjoy the mocking shenanigans that follow.
        """

        # Step the first: Mock the status request
        initial_name = 'vlan_bob_192.168.222'
        initial_desc = 'vlan_bob_192.168.222 description'
        status_uri = '/v2-experimental/operations/xxx/status/id'
        network_uri = '/v2-experimental/networks/xxx/dcx/54321'

        mock_request = mock.MagicMock()
        mock_request.uri = status_uri
        status_output = {
            'requestType': 'blueprintOperation',
            'status': 'succeeded',
            'summary': {
                'blueprintId':
                12345,
                'locationId':
                'DCx',
                'links': [{
                    'href': network_uri,
                    'id': network_id,
                    'rel': 'network'
                }]
            }
        }

        # Step the Second: Mock out the two API calls
        new_network = {
            'name': initial_name,
            'links': [],
            'vlan': 'bob',
            'id': network_id,
            'netmask': '255.255.255.0',
            'cidr': '192.168.222.0/24',
            'type': 'private',
            'gateway': '192.168.222.1',
            'description': initial_desc
        }

        response_map = {status_uri: status_output, network_uri: new_network}

        self.network.clc.v2.API.Call = mock.MagicMock(
            side_effect=lambda x, uri: response_map[uri]
            if uri in response_map else 'doing it wrong')

        # Step the Third: Mock the instantiation of a v2 Network object
        mock_network = mock.MagicMock()
        mock_network.id = network_id
        mock_network.name = initial_name
        mock_network.data = new_network
        self.network.clc.v2.Network = mock.MagicMock(return_value=mock_network)

        # Step the Fourth: Mock the wait/create calls
        mock_requests = mock.MagicMock()
        mock_requests.requests = [mock_request]
        mock_requests.WaitUntilComplete = mock.MagicMock(return_value=0)
        self.network.clc.v2.Network.Create = mock.MagicMock(
            return_value=mock_requests)
        mock_update.return_value = True, mock_network

        return status_uri, network_uri, mock_network

    @patch.object(ClcNetwork, '_update_network')
    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_updates_network_after_create_wait_if_provided_name_or_desc(
            self, mock_set_creds, mock_update):
        with patch.object(ClcNetwork,
                          '_populate_networks',
                          return_value=self.mock_nets) as mock_nets:
            network_id = 24601
            uri1, uri2, mock_network = self.ugly_setup(mock_update, network_id)
            new_name = "mocketymockmock"
            new_desc = "mockerymockmockdesc"
            self.module.params = {
                'name': new_name,
                'desc': new_desc,
                'location': 'mock_loc'
            }
            self.network.process_request()

            self.assertEqual(2, self.network.clc.v2.API.Call.call_count)
            self.network.clc.v2.API.Call.assert_any_call('GET', uri1)
            self.network.clc.v2.API.Call.assert_called_with('GET', uri2)
            self.network.clc.v2.Network.assert_called_once_with(
                network_id, network_obj=mock_network.data)
            mock_update.assert_called_once_with(mock_network,
                                                self.module.params)

    @patch.object(ClcNetwork, '_update_network')
    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_skips_update_after_create_if_no_name_or_desc_are_provided(
            self, mock_set_creds, mock_update):
        with patch.object(ClcNetwork,
                          '_populate_networks',
                          return_value=self.mock_nets) as mock_nets:
            network_id = 24601
            uri1, uri2, mock_network = self.ugly_setup(mock_update, network_id)
            new_name = "mocketymockmock"
            new_desc = "mockerymockmockdesc"
            self.module.params = {'location': 'mock_loc'}
            self.network.process_request()

            self.assertEqual(2, self.network.clc.v2.API.Call.call_count)
            self.network.clc.v2.API.Call.assert_any_call('GET', uri1)
            self.network.clc.v2.API.Call.assert_called_with('GET', uri2)
            self.network.clc.v2.Network.assert_called_once_with(
                network_id, network_obj=mock_network.data)
            mock_update.assert_not_called()

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_reports_failure_when_create_fails(
            self, mock_set_creds):
        with patch.object(ClcNetwork,
                          '_populate_networks',
                          return_value=self.mock_nets) as mock_nets:
            mock_request = mock.MagicMock()
            mock_request.WaitUntilComplete = mock.MagicMock(return_value=1)
            self.network.clc.v2.Network.Create = mock.MagicMock(
                return_value=mock_request)
            self.module.params = {'location': 'mock_loc'}

            self.network.process_request()

            self.assertEqual(1, mock_request.WaitUntilComplete.call_count)
            self.module.fail_json.assert_called_once_with(
                msg="Unable to create network")

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_skips_wait_when_wait_false(
            self, mock_set_creds):
        with patch.object(ClcNetwork,
                          '_populate_networks',
                          return_value=self.mock_nets) as mock_nets:
            mock_request = mock.MagicMock()
            mock_request.WaitUntilComplete = mock.MagicMock(return_value=0)
            self.network.clc.v2.Network.Create = mock.MagicMock(
                return_value=mock_request)
            self.module.params = {'location': 'mock_loc', 'wait': False}

            self.network.process_request()

            self.assertEqual(0, mock_request.WaitUntilComplete.call_count)

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_calls_update_when_network_exists_and_is_not_current(
            self, mock_set_creds):
        with patch.object(ClcNetwork,
                          '_populate_networks',
                          return_value=self.mock_nets):
            name = 'ShinyNewName'
            desc = 'ShinyNewDescription'
            self.network.clc.v2.Network.Create = mock.MagicMock()
            self.existing_net.Update = mock.MagicMock()
            self.module.params = {
                'id': 'existing',
                'name': name,
                'description': desc,
                'location': 'mock_loc',
            }

            self.network.process_request()

            self.assertEqual(0, self.network.clc.v2.Network.Create.call_count)
            self.existing_net.Update.assert_called_once_with(
                name, description=desc, location='mock_loc')

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_calls_update_with_description_when_name_not_provided(
            self, mock_set_creds):
        with patch.object(ClcNetwork,
                          '_populate_networks',
                          return_value=self.mock_nets):
            desc = 'ShinyNewDescription'
            self.network.clc.v2.Network.Create = mock.MagicMock()
            self.existing_net.Update = mock.MagicMock()
            self.module.params = {
                'id': 'existing',
                'description': desc,
                'location': 'mock_loc',
            }

            self.network.process_request()

            self.assertEqual(0, self.network.clc.v2.Network.Create.call_count)
            self.existing_net.Update.assert_called_once_with(
                'existing', description=desc, location='mock_loc')

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_calls_update_when_network_exists_and_only_name_is_not_current(
            self, mock_set_creds):
        with patch.object(ClcNetwork,
                          '_populate_networks',
                          return_value=self.mock_nets):
            name = 'ShinyNewName'
            desc = 'ShinyNewDescription'
            self.network.clc.v2.Network.Create = mock.MagicMock()
            self.existing_net.Update = mock.MagicMock()
            self.module.params = {
                'id': 'existing',
                'name': name,
                'location': 'mock_loc',
            }

            self.network.process_request()

            self.assertEqual(0, self.network.clc.v2.Network.Create.call_count)
            self.existing_net.Update.assert_called_once_with(
                name, location='mock_loc')

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_creates_and_exits_with_expected_network(
            self, mock_set_creds):
        with patch.object(ClcNetwork,
                          '_populate_networks',
                          return_value=self.mock_nets):
            mock_new = mock.MagicMock()
            mock_new.id = '12345'
            mock_new.alias = 'my_alias'
            mock_new.data = {'id': 'working', 'field': 'value'}
            self.network.clc.v2.Network = mock.MagicMock(return_value=mock_new)

            mock_request = mock.MagicMock()
            mock_request.WaitUntilComplete = mock.MagicMock(return_value=0)
            self.network.clc.v2.Network.Create = mock.MagicMock(
                return_value=mock_request)
            self.module.params = {'id': 'working', 'location': 'mock_loc'}

            self.network.process_request()

            self.module.exit_json.assert_called_once_with(
                changed=True, network=mock_new.data)

    def update_data(self, payload):
        self.existing_net.data = payload

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_updates_and_exits_with_expected_network(
            self, mock_set_creds):
        with patch.object(ClcNetwork,
                          '_populate_networks',
                          return_value=self.mock_nets):
            new_name = 'new_name'
            mock_update = self.existing_net
            mock_update.alias = 'my_alias'
            mock_update.data = {'id': 'existing', 'field': 'value'}

            expected = mock_update.data
            expected['name'] = new_name

            self.existing_net.Update = mock.MagicMock(
                side_effect=self.update_data(expected))
            self.module.params = {
                'id': 'existing',
                'name': new_name,
                'location': 'mock_loc'
            }

            self.network.process_request()

            self.module.exit_json.assert_called_once_with(changed=True,
                                                          network=expected)

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_present_exits_with_expected_request_when_wait_false(
            self, mock_set_creds):
        with patch.object(ClcNetwork,
                          '_populate_networks',
                          return_value=self.mock_nets):
            op_id = "operationId"
            op_uri = "/v2-experimental/operations/xxx/status/operationId"
            mock_request = mock.MagicMock()
            mock_request.id = op_id
            mock_request.uri = op_uri
            mock_requests = create_autospec(clc_sdk.v2.Requests)
            mock_requests.requests = [mock_request]
            self.network.clc.v2.Network.Create = mock.MagicMock(
                return_value=mock_requests)
            self.module.params = {'location': 'mock_loc', 'wait': False}

            self.network.process_request()

            expected = {"id": op_id, "uri": op_uri}

            self.module.exit_json.assert_called_once_with(changed=True,
                                                          network=expected)

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_for_delete_calls_sdk_delete_and_reports_change(
            self, mock_set_creds):
        with patch.object(ClcNetwork,
                          '_populate_networks',
                          return_value=self.mock_nets) as mock_nets:
            self.existing_net.Delete = mock.MagicMock()
            self.module.params = {
                'state': 'absent',
                'id': 'existing',
                'location': 'mock_loc'
            }

            self.network.process_request()

            self.existing_net.Delete.assert_called_once_with(
                location="mock_loc")
            self.module.exit_json.assert_called_once_with(changed=True,
                                                          network=None)

    @patch.object(ClcNetwork, '_set_clc_credentials_from_env')
    def test_process_request_for_delete_returns_no_change_when_network_not_found(
            self, mock_set_creds):
        with patch.object(ClcNetwork,
                          '_populate_networks',
                          return_value=self.mock_nets) as mock_nets:
            self.existing_net.Delete = mock.MagicMock()
            self.module.params = {
                'state': 'absent',
                'id': 'non-existing',
                'location': 'mock_loc'
            }

            self.network.process_request()

            self.assertEqual(0, self.existing_net.Delete.call_count)
            self.module.exit_json.assert_called_once_with(changed=False,
                                                          network=None)
 def test_set_clc_credentials_w_no_creds(self):
     with patch.dict('os.environ', {}, clear=True):
         under_test = ClcNetwork(self.module)
         under_test._set_clc_credentials_from_env()
     self.assertEqual(self.module.fail_json.called, True)
 def test_set_clc_credentials_w_api_url(self, mock_clc_sdk):
     with patch.dict('os.environ', {'CLC_V2_API_URL': 'dummyapiurl'}):
         under_test = ClcNetwork(self.module)
         under_test._set_clc_credentials_from_env()
         self.assertEqual(under_test.clc.defaults.ENDPOINT_URL_V2,
                          'dummyapiurl')