Fix Bug 2199 Fixing ns update operation for KNF instances

This patch enables ns update operations on KNF instances which are deployed with Helm chart
and using .charm zipped files.

Change-Id: I6c598868ae81243ef598ae5b7df88e26a5b870c0
Signed-off-by: aticig <gulsum.atici@canonical.com>
diff --git a/osm_lcm/tests/test_lcm_utils.py b/osm_lcm/tests/test_lcm_utils.py
index 6067b2d..71ebab1 100644
--- a/osm_lcm/tests/test_lcm_utils.py
+++ b/osm_lcm/tests/test_lcm_utils.py
@@ -16,7 +16,8 @@
 # contact: alfonso.tiernosepulveda@telefonica.com
 ##
 import logging
-from unittest.mock import Mock, patch, MagicMock
+import tempfile
+from unittest.mock import Mock, patch, MagicMock, mock_open
 from unittest import TestCase
 
 from osm_common.msgkafka import MsgKafka
@@ -29,6 +30,10 @@
 from zipfile import BadZipfile
 
 
+tmpdir = tempfile.mkdtemp()[1]
+tmpfile = tempfile.mkstemp()[1]
+
+
 class TestLcmBase(TestCase):
 
     test_nsr_id = "f48163a6-c807-47bc-9682-f72caef5af85"
@@ -52,6 +57,7 @@
         self.my_ns = LcmBase(self.msg, self.logger)
         self.my_ns.fs = self.fs
         self.my_ns.db = self.db
+        self.hexdigest = "031edd7d41651593c5fe5c006f"
 
     def test_get_charm_name_successfully(self):
         instance = self.my_ns
@@ -245,3 +251,196 @@
                 self.assertEqual(mock_charm_path.call_count, 1)
                 self.assertEqual(mock_metadata_file.call_count, 1)
                 self.assertEqual(mock_charm_name.call_count, 1)
+
+    @patch("builtins.open", new_callable=mock_open(read_data="charm content"))
+    @patch("osm_lcm.lcm_utils.hashlib")
+    def test_calculate_charm_hash_sucessfully(self, mock_hashlib, mocking_open):
+        """Calculate charm hash successfully."""
+        charm = tmpfile
+        hexdigest = self.hexdigest
+        mock_file_hash = MagicMock()
+        mock_hashlib.md5.return_value = mock_file_hash
+        mock_file_hash.hexdigest.return_value = hexdigest
+        result = LcmBase.calculate_charm_hash(charm)
+        self.assertEqual(result, hexdigest)
+        self.assertEqual(mocking_open.call_count, 1)
+        self.assertEqual(mock_file_hash.update.call_count, 1)
+        self.assertEqual(mock_file_hash.hexdigest.call_count, 1)
+        self.assertEqual(mock_hashlib.md5.call_count, 1)
+
+    @patch("builtins.open", new_callable=mock_open(read_data="charm content"))
+    @patch("osm_lcm.lcm_utils.hashlib")
+    def test_calculate_charm_hash_open_raises(self, mock_hashlib, mocking_open):
+        """builtins.open raises exception."""
+        charm = tmpfile
+        hexdigest = self.hexdigest
+        mock_file_hash = MagicMock()
+        mock_hashlib.md5.return_value = mock_file_hash
+        mock_file_hash.hexdigest.return_value = hexdigest
+        mocking_open.side_effect = IOError
+        with self.assertRaises(IOError):
+            LcmBase.calculate_charm_hash(charm)
+        self.assertEqual(mocking_open.call_count, 1)
+        mock_file_hash.update.assert_not_called()
+        mock_file_hash.hexdigest.assert_not_called()
+        self.assertEqual(mock_hashlib.md5.call_count, 1)
+
+    @patch("builtins.open", new_callable=mock_open(read_data="charm content"))
+    @patch("osm_lcm.lcm_utils.hashlib")
+    def test_calculate_charm_filehash_update_raises(self, mock_hashlib, mocking_open):
+        """Filehash update raises exception."""
+        charm = tmpfile
+        hexdigest = self.hexdigest
+        mock_file_hash = MagicMock()
+        mock_file_hash.update.side_effect = Exception
+        mock_hashlib.md5.return_value = mock_file_hash
+        mock_file_hash.hexdigest.return_value = hexdigest
+        with self.assertRaises(Exception):
+            LcmBase.calculate_charm_hash(charm)
+        self.assertEqual(mocking_open.call_count, 1)
+        self.assertEqual(mock_file_hash.update.call_count, 1)
+        mock_file_hash.hexdigest.assert_not_called()
+        self.assertEqual(mock_hashlib.md5.call_count, 1)
+
+    @patch("builtins.open", new_callable=mock_open(read_data="charm content"))
+    @patch("osm_lcm.lcm_utils.hashlib")
+    def test_calculate_charm_filehash_hexdigest_raises(
+        self, mock_hashlib, mocking_open
+    ):
+        """Filehash hexdigest raises exception."""
+        charm = tmpfile
+        mock_file_hash = MagicMock()
+        mock_hashlib.md5.return_value = mock_file_hash
+        mock_file_hash.hexdigest.side_effect = Exception
+        with self.assertRaises(Exception):
+            LcmBase.calculate_charm_hash(charm)
+        self.assertEqual(mocking_open.call_count, 1)
+        self.assertEqual(mock_file_hash.update.call_count, 1)
+        mock_file_hash.hexdigest.assert_called_once()
+        self.assertEqual(mock_hashlib.md5.call_count, 1)
+        mock_file_hash.update.assert_called_once()
+
+    @patch("builtins.open", new_callable=mock_open(read_data="charm content"))
+    @patch("osm_lcm.lcm_utils.hashlib")
+    def test_calculate_charm_filehash_hashlib_md5_raises(
+        self, mock_hashlib, mocking_open
+    ):
+        """Filehash hashlib md5 raises exception."""
+        charm = tmpfile
+        mock_hashlib.md5.side_effect = Exception
+        with self.assertRaises(Exception):
+            LcmBase.calculate_charm_hash(charm)
+        self.assertEqual(mock_hashlib.md5.call_count, 1)
+        mocking_open.assert_not_called()
+
+    @patch("builtins.open", new_callable=mock_open(read_data="charm content"))
+    @patch("osm_lcm.lcm_utils.hashlib")
+    def test_calculate_charm_hash_file_does_not_exist(self, mock_hashlib, mocking_open):
+        """Calculate charm hash, charm file does not exist."""
+        file = None
+        mock_file_hash = MagicMock()
+        mock_hashlib.md5.return_value = mock_file_hash
+        mocking_open.side_effect = FileNotFoundError
+        with self.assertRaises(FileNotFoundError):
+            LcmBase.calculate_charm_hash(file)
+        self.assertEqual(mocking_open.call_count, 1)
+        mock_file_hash.update.assert_not_called()
+        mock_file_hash.hexdigest.assert_not_called()
+        self.assertEqual(mock_hashlib.md5.call_count, 1)
+
+    @patch("osm_lcm.lcm_utils.LcmBase.calculate_charm_hash")
+    def test_compare_charm_hash_charm_changed(self, mock_calculate_charm_hash):
+        """Compare charm hash, charm files are different."""
+        output = True
+        charm1, charm2 = tmpfile, tmpfile
+        mock_calculate_charm_hash.side_effect = [
+            self.hexdigest,
+            "0dd7d4173747593c5fe5c006f",
+        ]
+        result = LcmBase.compare_charm_hash(charm1, charm2)
+        self.assertEqual(output, result)
+        self.assertEqual(mock_calculate_charm_hash.call_count, 2)
+
+    @patch("osm_lcm.lcm_utils.LcmBase.calculate_charm_hash")
+    def test_compare_charm_hash_charm_is_same(self, mock_calculate_charm_hash):
+        """Compare charm hash, charm files are same."""
+        output = False
+        charm1 = charm2 = tmpfile
+        mock_calculate_charm_hash.side_effect = [
+            self.hexdigest,
+            self.hexdigest,
+        ]
+        result = LcmBase.compare_charm_hash(charm1, charm2)
+        self.assertEqual(output, result)
+        self.assertEqual(mock_calculate_charm_hash.call_count, 2)
+
+    @patch("osm_lcm.lcm_utils.LcmBase.calculate_charm_hash")
+    def test_compare_charm_hash_one_charm_is_not_valid(self, mock_calculate_charm_hash):
+        """Compare charm hash, one charm file is not valid."""
+        charm1, charm2 = tmpdir, None
+        mock_calculate_charm_hash.side_effect = [
+            self.hexdigest,
+            FileNotFoundError,
+        ]
+
+        with self.assertRaises(FileNotFoundError):
+            LcmBase.compare_charm_hash(charm1, charm2)
+        self.assertEqual(mock_calculate_charm_hash.call_count, 2)
+
+    @patch("osm_lcm.lcm_utils.LcmBase.calculate_charm_hash")
+    def test_compare_charm_hash_both_charms_are_not_valid(
+        self, mock_calculate_charm_hash
+    ):
+        """Compare charm hash, both charm files are not valid."""
+        charm1, charm2 = None, None
+        mock_calculate_charm_hash.side_effect = [IOError, IOError]
+        with self.assertRaises(IOError):
+            LcmBase.compare_charm_hash(charm1, charm2)
+        self.assertEqual(mock_calculate_charm_hash.call_count, 1)
+
+    @patch("osm_lcm.lcm_utils.checksumdir")
+    def test_compare_charmdir_charm_changed(self, mock_checksum):
+        """Compare charm directory hash, charms are changed."""
+        expected_output = True
+        charm_dir1, charm_dir2 = tmpdir, tmpdir
+        mock_checksum.dirhash.side_effect = [
+            self.hexdigest,
+            "031eddtrtr651593c5fe5c006f",
+        ]
+        result = LcmBase.compare_charmdir_hash(charm_dir1, charm_dir2)
+        self.assertEqual(expected_output, result)
+        self.assertEqual(mock_checksum.dirhash.call_count, 2)
+
+    @patch("osm_lcm.lcm_utils.checksumdir")
+    def test_compare_charmdir_charm_is_same(self, mock_checksum):
+        """Compare charm directory hash, charms are same."""
+        expected_output = False
+        charm_dir1 = charm_dir2 = tmpdir
+        mock_checksum.dirhash.side_effect = [
+            self.hexdigest,
+            self.hexdigest,
+        ]
+        result = LcmBase.compare_charmdir_hash(charm_dir1, charm_dir2)
+        self.assertEqual(expected_output, result)
+        self.assertEqual(mock_checksum.dirhash.call_count, 2)
+
+    @patch("osm_lcm.lcm_utils.checksumdir")
+    def test_compare_charmdir_one_charmdir_is_not_valid(self, mock_checksum):
+        """Compare charm directory hash, one charm directory is not valid."""
+        charm_dir1, charm_dir2 = tmpdir, None
+        mock_checksum.dirhash.side_effect = [
+            self.hexdigest,
+            FileNotFoundError,
+        ]
+        with self.assertRaises(FileNotFoundError):
+            LcmBase.compare_charmdir_hash(charm_dir1, charm_dir2)
+        self.assertEqual(mock_checksum.dirhash.call_count, 2)
+
+    @patch("osm_lcm.lcm_utils.checksumdir")
+    def test_compare_charmdir_both_charmdirs_are_not_valid(self, mock_checksum):
+        """Compare charm directory hash, both charm directories are not valid."""
+        charm_dir1, charm_dir2 = None, None
+        mock_checksum.dirhash.side_effect = [FileNotFoundError, FileNotFoundError]
+        with self.assertRaises(FileNotFoundError):
+            LcmBase.compare_charmdir_hash(charm_dir1, charm_dir2)
+        self.assertEqual(mock_checksum.dirhash.call_count, 1)