"""Test the dirac-transformation-replication script and helper"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import unittest

from mock import MagicMock as Mock, patch

from DIRAC import S_OK, S_ERROR

from DIRAC.TransformationSystem.Utilities.ReplicationTransformation import createDataTransformation
from DIRAC.TransformationSystem.Utilities.ReplicationCLIParameters import Params

__RCSID__ = "$Id$"

GET_VOMS = "DIRAC.TransformationSystem.Utilities.ReplicationCLIParameters.getVOMSVOForGroup"
GET_PROXY = "DIRAC.TransformationSystem.Utilities.ReplicationCLIParameters.getProxyInfo"


def getProxyMock(success=True):
  """ return value for getProxy """
  if success:
    return Mock(return_value=S_OK({'groupProperties': ['ProductionManagement'],
                                   'group': 'clic_prod',
                                   }))
  return Mock(return_value=S_ERROR("Failed"))


def opMock():
  """ return mock for config operations """
  opmock = Mock()
  opmock.getOptionsDict.return_value = S_OK({'trans': 'ProdID'})
  opmock.getValue.return_value = 'ProdID'
  return Mock(return_value=opmock)


class TestMoving(unittest.TestCase):
  """Test the creation of moving transformation"""

  def setUp(self):
    self.tClientMock = Mock()
    # self.tClientMock.createTransformationInputDataQuery.return_value = S_OK()
    self.tClientMock.createTransformationMetaQuery.return_value = S_OK()
    self.tMock = Mock(return_value=self.tClientMock)

  def tearDown(self):
    pass

  def test_createRepl_Broadcast(self):
    """ test creating transformation """
    tSE = "Target-SRM"
    sSE = "Source-SRM"
    prodID = 12345
    trmodule = "DIRAC.TransformationSystem.Client.Transformation.Transformation"
    with patch(trmodule + ".getTransformation", new=Mock(return_value=S_OK({}))), \
            patch(trmodule + ".addTransformation", new=Mock(return_value=S_OK())), \
            patch(trmodule + "._Transformation__setSE", new=Mock(return_value=S_OK())):
      ret = createDataTransformation('Moving', tSE, sSE, 'prodID', prodID, enable=True)
    self.assertTrue(ret['OK'], ret.get('Message', ""))
    self.assertEqual(ret['Value'].getPlugin().get('Value'), 'Broadcast')
    self.assertEqual(ret['Value'].inputMetaQuery, {'prodID': prodID})

  def test_createRepl_NoSource(self):
    """ test creating transformation """
    tSE = 'Target-SRM'
    sSE = ''
    prodID = 12345
    trmodule = 'DIRAC.TransformationSystem.Client.Transformation.Transformation'
    with patch(trmodule + '.getTransformation', new=Mock(return_value=S_OK({}))), \
            patch(trmodule + '.addTransformation', new=Mock(return_value=S_OK())), \
            patch(trmodule + '._Transformation__setSE', new=Mock(return_value=S_OK())):
      ret = createDataTransformation('Moving', tSE, sSE, 'prodID', prodID, enable=True)
    self.assertTrue(ret['OK'], ret.get('Message', ''))
    self.assertEqual(ret['Value'].getPlugin().get('Value'), 'Broadcast')


  def test_createRepl_Dry(self):
    """ test creating transformation """
    tSE = "Target-SRM"
    sSE = "Source-SRM"
    prodID = 12345
    trmodule = "DIRAC.TransformationSystem.Client.Transformation.Transformation"
    with patch(trmodule + ".getTransformation", new=Mock(return_value=S_OK({}))), \
            patch(trmodule + ".addTransformation", new=Mock(return_value=S_OK())), \
            patch(trmodule + "._Transformation__setSE", new=Mock(return_value=S_OK())):
      ret = createDataTransformation('Moving', tSE, sSE, 'prodID', prodID, enable=False, extraData={})
    self.assertTrue(ret['OK'], ret.get('Message', ""))

  def test_createRepl_2(self):
    """ test creating transformation """
    tSE = "Target-SRM"
    sSE = "Source-SRM"
    prodID = 12345
    trmodule = "DIRAC.TransformationSystem.Client.Transformation.Transformation"
    with patch(trmodule + ".getTransformation", new=Mock(return_value=S_OK({}))), \
            patch(trmodule + ".addTransformation", new=Mock(return_value=S_OK())), \
            patch(trmodule + "._Transformation__setSE", new=Mock(return_value=S_OK())):
      ret = createDataTransformation('Moving', tSE, sSE, 'prodID', prodID, extraname="extraName", enable=True)
    self.assertTrue(ret['OK'], ret.get('Message', ""))

  def test_createRepl_BadFlavour(self):
    """ test creating transformation """
    tSE = "Target-SRM"
    sSE = "Source-SRM"
    prodID = 12345
    trmodule = "DIRAC.TransformationSystem.Client.Transformation.Transformation"
    with patch(trmodule + ".getTransformation", new=Mock(return_value=S_OK({}))), \
            patch(trmodule + ".addTransformation", new=Mock(return_value=S_OK())), \
            patch(trmodule + "._Transformation__setSE", new=Mock(return_value=S_OK())):
      ret = createDataTransformation('Smelly', tSE, sSE, 'prodID', prodID, extraname="extraName", enable=True)
    self.assertFalse(ret['OK'], ret.get('Message', ""))
    self.assertIn('Unsupported flavour', ret['Message'])

  def test_createRepl_SEFail_1(self):
    """ test creating transformation """
    tSE = "Target-SRM"
    sSE = "Source-SRM"
    prodID = 12345
    trmodule = "DIRAC.TransformationSystem.Client.Transformation.Transformation"
    with patch(trmodule + ".getTransformation", new=Mock(return_value=S_OK({}))), \
            patch(trmodule + ".addTransformation", new=Mock(return_value=S_OK())), \
            patch(trmodule + "._Transformation__setSE", new=Mock(side_effect=(S_OK(), S_ERROR()))):
      ret = createDataTransformation('Moving', tSE, sSE, 'prodID', prodID, enable=True)
    self.assertFalse(ret['OK'], str(ret))
    self.assertIn("TargetSE not valid", ret['Message'])

  def test_createRepl_SEFail_2(self):
    """ test creating transformation """
    tSE = "Target-SRM"
    sSE = "Source-SRM"
    prodID = 12345
    trmodule = "DIRAC.TransformationSystem.Client.Transformation.Transformation"
    with patch(trmodule + ".getTransformation", new=Mock(return_value=S_OK({}))), \
            patch(trmodule + ".addTransformation", new=Mock(return_value=S_OK())), \
            patch(trmodule + "._Transformation__setSE", new=Mock(side_effect=(S_ERROR(), S_ERROR()))):
      ret = createDataTransformation('Moving', tSE, sSE, 'prodID', prodID, enable=True)
    self.assertFalse(ret['OK'], str(ret))
    self.assertIn("SourceSE not valid", ret['Message'])

  def test_createRepl_addTrafoFail_(self):
    """ test creating transformation """
    tSE = "Target-SRM"
    sSE = "Source-SRM"
    prodID = 12345
    trmodule = "DIRAC.TransformationSystem.Client.Transformation.Transformation"
    with patch(trmodule + ".getTransformation", new=Mock(return_value=S_OK({}))), \
            patch(trmodule + ".addTransformation", new=Mock(return_value=S_ERROR("Cannot add Trafo"))), \
            patch(trmodule + "._Transformation__setSE", new=Mock(return_value=S_OK())):
      ret = createDataTransformation('Moving', tSE, sSE, 'prodID', prodID, enable=True)
    self.assertFalse(ret['OK'], str(ret))
    self.assertIn("Cannot add Trafo", ret['Message'])

  def test_createRepl_createTrafoFail_(self):
    """ test creating transformation """
    tSE = "Target-SRM"
    sSE = "Source-SRM"
    prodID = 12345
    trmodule = "DIRAC.TransformationSystem.Client.Transformation.Transformation"
    with patch(trmodule + ".getTransformation", new=Mock(return_value=S_OK({}))), \
            patch(trmodule + ".addTransformation", new=Mock(return_value=S_ERROR('Failed to add IMQ'))), \
            patch(trmodule + "._Transformation__setSE", new=Mock(return_value=S_OK())):
      ret = createDataTransformation('Moving', tSE, sSE, 'prodID', prodID, enable=True)
    self.assertFalse(ret['OK'], str(ret))
    self.assertIn("Failed to add IMQ", ret['Message'])


class TestParams(unittest.TestCase):
  """Test the parameters for the moving creation script"""

  def setUp(self):
    self.arguments = []
    self.sMock = Mock()
    self.sMock.getPositionalArgs.return_value = self.arguments
    self.params = Params()

  def tearDown(self):
    pass

  @patch(GET_PROXY, new=getProxyMock())
  @patch(GET_VOMS, new=Mock(return_value='clic'))
  def test_checkSettings(self):
    self.arguments = ['12345', "TargetSE"]
    self.sMock.getPositionalArgs.return_value = self.arguments
    ret = self.params.checkSettings(self.sMock)
    self.assertTrue(ret['OK'], ret.get("Message", ''))
    self.assertEqual(self.params.metaValues, ['12345'])
    self.assertEqual(self.params.sourceSE, '')
    self.assertEqual(self.params.targetSE, ["TargetSE"])

  @patch(GET_PROXY, new=getProxyMock())
  @patch(GET_VOMS, new=Mock(return_value='clic'))
  def test_setMetadata(self):
    ret = self.params.setMetadata("Datatype:GEN, Energy: 124")
    self.assertTrue(ret['OK'], ret.get("Message", ''))
    self.assertEqual(self.params.extraData, {'Datatype': 'GEN',
                                             'Energy': '124'})

  @patch(GET_PROXY, new=getProxyMock())
  @patch(GET_VOMS, new=Mock(return_value='clic'))
  def test_checkSettings_FailArgumentSize(self):
    self.arguments = ['12345', "TargetSE", 'Foo']
    self.sMock.getPositionalArgs.return_value = self.arguments
    ret = self.params.checkSettings(self.sMock)
    self.assertFalse(ret['OK'], str(ret))
    self.assertTrue(any("ERROR: Wrong number of arguments" in msg for msg in self.params.errorMessages))

  @patch(GET_PROXY, new=getProxyMock(False))
  @patch(GET_VOMS, new=Mock(return_value='clic'))
  def test_FailProxy(self):
    self.arguments = ['12345', "TargetSE"]
    self.sMock.getPositionalArgs.return_value = self.arguments
    ret = self.params.checkSettings(self.sMock)
    self.assertFalse(ret['OK'], str(ret))
    self.assertTrue(any("ERROR: No Proxy" in msg for msg in self.params.errorMessages), str(self.params.errorMessages))

  @patch(GET_PROXY, new=getProxyMock(True))
  @patch(GET_VOMS, new=Mock(return_value=''))
  def test_FailProxy2(self):
    self.arguments = ['12345', "TargetSE"]
    self.sMock.getPositionalArgs.return_value = self.arguments
    ret = self.params.checkSettings(self.sMock)
    self.assertFalse(ret['OK'], str(ret))
    self.assertTrue(any("ERROR: ProxyGroup" in msg for msg in self.params.errorMessages),
                    str(self.params.errorMessages))

  def test_setExtraName(self):
    ret = self.params.setExtraname("extraName")
    self.assertTrue(ret['OK'], ret.get('Message', ""))
    self.assertEqual("extraName", self.params.extraname)
