Repository: learningequality/kolibri

Issue:
Add regression testing for channel update deletion behaviour
Ref: https://github.com/learningequality/kolibri/pull/5853/files/b0104f3ef0e978f41beddf090240c4f1b5cafe04..94c5800705a4f5f5b5295de4fb75b9d7e4a75c6e#r329181611

Add a test to ensure that deleting during an upgrade proceeds properly.


Discussion:
Hi @indirectlylit @rtibbles I would like to take this up.

I had a doubt as to where should I place the tests. Should it be in a new file (something like `test_channel_update_deletion.py`) or in the `test_channel_import.py`?
@YashJipkate I think if it's more convenient, you can just add a new test case to an existing module like `test_channel_import`
@YashJipkate Are you working on this issue? If not, can I work on it?
@muhammadalics currently no, but I was planning to resume it post the GSoC application period. But if you want to work on it, then feel free to go ahead. And let us know if you are up for it. 
Hii i would like to work on this issue please assign me the issue @marcellamaki 
Hello @Pursottam6003, thank you for your interest. As you volunteered for more issues and already have some of them assigned, I'm leaving this unassigned for now in case someone else wanted to tackle it as you're working on other issues. When your plate is empty, if this issue is still available, please remind yourself here and we can assign it to you.
Hi, is this issue still open? I would like to work on it.
Yes, these tests have not been written yet! I will assign you.
Hey,
Can you help me with how to write the regression test.
Hi @nikkuAg, what exactly would you need to know at this point?
@MisRob, I wanted to know how to write the test. Could you share some resources?
Hi @nikkuAg There are [some available tests](https://github.com/learningequality/kolibri/blame/e7c0d65526e09e7125c32c8b695da9f7caecf6de/kolibri/core/content/test/test_channel_import.py#L645) for the deletion of channel related metadata during an upgrade. The first step would involve looking over these tests to identify any additional areas that have not been covered. You may also find helpful information about running automated tests in Kolibri [here](https://kolibri-dev.readthedocs.io/en/develop/getting_started.html#automated-testing:~:text=Kolibri%20comes%20with%20a%20Python%20test%20suite%20based%20on%20pytest.%20To%20run%20all%20back%2Dend%20tests%3A). I hope this helps!
Can I be assigned this issue?

Hi @aarishshahmohsin - yes, thank you for your interest. I will assign you. Let us know if you have any questions. 

Learning Equality will be closed for the end of the year from December 22 - January 2. Our team may be slower to respond during this time.
Hey @marcellamaki, I went through the whole conversation of the issue and it seems to me that the task still remains to work as I also didn't find any linked PR with the issue. If it's still open can you please assign it to me? I would love to contribute.
Hi @yashpandey002! Sure!  I have assigned the issue to you. Thanks for your interest in contributing to Kolibri :open_hands: Please let us know if you have any questions.
Thanks, @AlexVelezLl, and ya I will let you know if I have any queries👐
Hey @AlexVelezLl, actually I am having difficulty setting up the repository locally, it's showing me some errors related to some Python libraries not found. 

I went through the Github discussions but didn't find any solution to my problem and now I am confused about where to ask this query as it is related to the setup and not issue-specific. Please guide me about this.
Hi @yashpandey002! Did you follow the following [step](https://kolibri-dev.readthedocs.io/en/develop/getting_started.html#install-python-dependencies) and install the Python dependencies? 
Hey @ozer550 actually I was following the setup steps and when I tried setting up the virtual environment with pyenv(as it is recommended in docs) by following these instructions: https://kolibri-dev.readthedocs.io/en/develop/howtos/installing_pyenv.html I got some errors and not able to set up the virtual environment

- I am using Fish shell so I did all the required steps for it and successfully installed the Pyenv.
- But when I tried installing a Python version using pyenv by this command: pyenv install 3.9.9, it gave me a long error of some libraries not found.
- The libraries this error pointing to are: bzip2, ncurses, libffi, and OpenSSL, but when I checked I found that all the libraries are already installed

If you want I can show you the exact error but I am not sure about how should I do it, like should I copy-paste the whole error here?
I was wondering if you installed all the pre-requisites mentioned by pyenv [here](https://github.com/pyenv/pyenv/wiki/Common-build-problems#prerequisites)?

Looks like after following the prerequisite instructions I have successfully installed the 3.9.9 version of Python with pyenv but now when I try to activate the virtual environment by this command: "pyenv activate kolibri-py3.9" it showing me: "pyenv-virtualenv: prompt changing not working for fish" and when I tried it again it showed: "pyenv-virtualenv: version `kolibri-py3.9' is already activated". So I am not sure if it is working fine or not?

I searched for the "prompt changing not working for fish" and found this thread: https://github.com/pyenv/pyenv/issues/1723 where it seems like they have closed it already 
If you type `python --version` if it outputs `3.9.9` then the venv should be activated (unless that's your system Python version!).
Thanks @rtibbles, when I executed the python --version command in Kolibri command it gave me 3.9.9(which I tried installing), and when I executed the same command in my global terminal it gave me 3.11.7, so now I am good to go right?
Seems so!
![image](https://github.com/learningequality/kolibri/assets/75162407/caa96ef2-b9fa-42f5-a019-676baf223ffd)
Can anyone please help me with this error, I can't exactly understand what it is trying to say, all I can understand is that the "yarn run build-base --mode=development --watch" command is failing.
The error is described in the line mentioning the `git describe --tags` command . For some reason you've tagged your version code in your repo and does not match current kolibri version schema.

https://git-scm.com/docs/git-describe shows the latest version tag in the git repository, I get `v0.16.0-beta10-116-gbad3d07cf2` in my local repository . I guess you have added more tags that are not in sync with the version file of the repo.

can i be assigned to this?

Sure! @thesujai. I will assign this issue to you :).
Hello 👋🏽 
Just to clarify my approach and my understanding
For a test case lets call it `ChannelImportDeleteTestCase`, I will have following methods(tests)(All centered arround `check_and_delete_existing_channel()`):

1. Test case when channel already exists
2. Test case to check and delete an existing channel during partial import
3. Test case to check and delete an existing channel with an older version(verifies that the appropriate methods are called to delete the old channel data)
4. Test case when the channel being imported has the same or newer version already present in the database.
5. Test case to check if the existing channel is deleted when the channel does not exist.

@rtibbles If my approach seems okay, then also let me know which branch to target the PR, it is often unclear with the labels
Yes, all looks correct. For (2) just to clarify that doing a partial import over a full import should not trigger a deletion, but doing a full import over a partial import should.

This work should be targeted to develop.

Resolving patch:
diff --git a/kolibri/core/content/utils/channel_import.py b/kolibri/core/content/utils/channel_import.py
--- a/kolibri/core/content/utils/channel_import.py
+++ b/kolibri/core/content/utils/channel_import.py
@@ -741,7 +741,9 @@ def check_and_delete_existing_channel(self):
                     )
                     return False
                 return True
-            elif current_version < self.channel_version or current_partial:
+            elif current_version is not None and (
+                current_version < self.channel_version or current_partial
+            ):
                 # We have an older version of this channel, so let's clean out the old stuff first
                 # Or we only have a partial import of this channel.
                 logger.info(


Test patch:
diff --git a/kolibri/core/content/test/test_channel_import.py b/kolibri/core/content/test/test_channel_import.py
--- a/kolibri/core/content/test/test_channel_import.py
+++ b/kolibri/core/content/test/test_channel_import.py
@@ -960,3 +960,77 @@ def tearDownClass(cls):
     @classmethod
     def setUpClass(cls):
         super(NoVersionv040ImportTestCase, cls).setUpClass()
+
+
+@patch("kolibri.core.content.utils.channel_import.Bridge")
+@patch("kolibri.core.content.utils.channel_import.logger")
+@patch("kolibri.core.content.utils.channel_import.select")
+@patch("kolibri.core.content.utils.channel_import.apps")
+class ChannelImportTestCase(ContentImportTestBase, TransactionTestCase):
+    name = CONTENT_SCHEMA_VERSION
+    legacy_schema = None
+
+    def setUp(self):
+        super(ChannelImportTestCase, self).setUp()
+        self.channel_id = "6199dde695db4ee4ab392222d5af1e5c"
+        self.channel_version = 2
+        self.current_channel = None
+
+    def tearDown(self):
+        return super().tearDown()
+
+    def test_channel_already_exists(
+        self, select_mock, logger_mock, apps_mock, BridgeMock
+    ):
+        self.current_channel = ChannelMetadata.objects.get(id=self.channel_id)
+        self.current_channel.version = self.channel_version
+        self.current_channel.save()
+        self.channel_import = ChannelImport(self.channel_id, "")
+        self.channel_import.channel_version = self.channel_version
+        result = self.channel_import.check_and_delete_existing_channel()
+        self.assertFalse(result)
+
+    def test_partial_import_no_deletion(
+        self, select_mock, logger_mock, apps_mock, BridgeMock
+    ):
+        self.current_channel = ChannelMetadata.objects.get(id=self.channel_id)
+        self.current_channel.version = self.channel_version
+        self.current_channel.save()
+        self.channel_import = ChannelImport(self.channel_id, "")
+        self.channel_import.channel_version = self.channel_version
+        self.channel_import.partial = True
+
+        result = self.channel_import.check_and_delete_existing_channel()
+        self.assertTrue(result)
+
+    def test_partial_import_with_deletion(
+        self, select_mock, logger_mock, apps_mock, BridgeMock
+    ):
+        # Simulate partial import with the same version
+        self.current_channel = ChannelMetadata.objects.get(id=self.channel_id)
+        self.current_channel.version = self.channel_version
+        self.current_channel.save()
+        self.channel_import = ChannelImport(self.channel_id, "")
+        self.channel_import.channel_version = self.channel_version - 1
+        self.channel_import.partial = True
+        result = self.channel_import.check_and_delete_existing_channel()
+        self.assertFalse(result)
+
+    def test_full_import_with_newer_version(
+        self, select_mock, logger_mock, apps_mock, BridgeMock
+    ):
+        # Simulate full import with a newer version
+        self.current_channel = ChannelMetadata.objects.get(id=self.channel_id)
+        self.current_channel.version = self.channel_version
+        self.current_channel.save()
+        self.channel_import = ChannelImport(self.channel_id, "")
+        self.channel_import.channel_version = self.channel_version + 1
+        result = self.channel_import.check_and_delete_existing_channel()
+        self.assertTrue(result)
+
+    def test_channel_not_exists(self, select_mock, logger_mock, apps_mock, BridgeMock):
+        # Simulate channel not existing in the database
+        self.channel_import = ChannelImport(self.channel_id, "")
+        self.channel_import.channel_version = self.channel_version
+        result = self.channel_import.check_and_delete_existing_channel()
+        self.assertTrue(result)