Repository: oppia/oppia

Issue:
Add validation for `MAX_COMMIT_MESSAGE_LENGTH`
Add validation for the maximum commit length (`MAX_COMMIT_MESSAGE_LENGTH`) to the commit logs and snapshot metadata models.


Discussion:
@vojtechjelinek is this issue already resolved? 
@DubeySandeep No
@vojtechjelinek I would like to work on this issue.
@vojtechjelinek Can you tell me where should I start with? Thanks!
@hardikkat24 Hi, you will need to modify https://github.com/oppia/oppia/blob/619c620d51f4af175c52d7dfe435c3dc70043f42/core/domain/base_model_validators.py#L694 and https://github.com/oppia/oppia/blob/619c620d51f4af175c52d7dfe435c3dc70043f42/core/domain/base_model_validators.py#L779 to include a check for the length of `commit_message` field in `BaseSnapshotMetadataModel` and `BaseCommitLogEntryModel`.

If this explanation is not enough please let me know.
@vojtechjelinek Thanks a lot! I have done as you said. But I have some questions:
1. Should I add tests in `prod_validators_test.py`?
2. How do i check that my validators are working correctly on my local machine?
@hardikkat24 
1. better to base_model_validators_test.py
2. you start the local server, log in as admin, navigate to admin page and the jobs tab, run the jobs there
@vojtechjelinek Thanks a lot!
But what I did was I added validator for `commit_message`'s length in `BaseCommitLogEntryModelValidator` and `BaseSnapshotMetadataModelValidator`.

Now I should test this code. So this can be done by adding tests in `base_model_validators_test.py` and running Jobs corresponding to `ExplorationCommitLogEntryModelValidatorTests` because I made changes in `BaseCommitLogEntryModelValidator`. 
But `base_model_validators_test.py` doesn't have any present tests for other validators. So is there any other file where I must add the tests.
I'm a bit confused in this. Please clarify. Thanks!
@hardikkat24 Okay, put the tests in prod_validators_test.py, we can discuss any move of these tests to other places once you open a PR.
@vojtechjelinek After I add the tests, then only the Jobs will show whether my approach was correct or not. Am I correct on this? Or can I test my approach without adding tests in the file.
As I said "you start the local server, log in as admin, navigate to admin page and the jobs tab, run the jobs there".

Resolving patch:
diff --git a/core/domain/base_model_validators.py b/core/domain/base_model_validators.py
--- a/core/domain/base_model_validators.py
+++ b/core/domain/base_model_validators.py
@@ -23,6 +23,7 @@
 import datetime
 import re
 
+from constants import constants
 from core.domain import cron_services
 from core.domain import rights_manager
 from core.platform import models
@@ -36,6 +37,7 @@
 
 ERROR_CATEGORY_COMMIT_CMD_CHECK = 'commit cmd check'
 ERROR_CATEGORY_COMMIT_STATUS_CHECK = 'post commit status check'
+ERROR_CATEGORY_COMMIT_MESSAGE_CHECK = 'commit message check'
 ERROR_CATEGORY_COUNT_CHECK = 'count check'
 ERROR_CATEGORY_CURRENT_TIME_CHECK = 'current time check'
 ERROR_CATEGORY_DATETIME_CHECK = 'datetime check'
@@ -766,6 +768,22 @@ def _validate_commit_cmds_schema(cls, item):
                     'command: %s failed with error: %s' % (
                         item.id, commit_cmd_dict, e))
 
+    @classmethod
+    def _validate_commit_message_length(cls, item):
+        """Validates that commit_message length is less than
+        MAX_COMMIT_MESSAGE_LENGTH.
+
+        Args:
+            item: datastore_services.Model. Entity to validate.
+        """
+
+        if item.commit_message and (
+                len(item.commit_message) > constants.MAX_COMMIT_MESSAGE_LENGTH):
+            cls._add_error(
+                ERROR_CATEGORY_COMMIT_MESSAGE_CHECK,
+                'Entity id %s: Commit message larger than accepted length'
+                % (item.id))
+
     @classmethod
     def validate(cls, item):
         """Run _fetch_field_name_to_external_model_references and all
@@ -778,6 +796,7 @@ def validate(cls, item):
 
         cls._validate_commit_type(item)
         cls._validate_commit_cmds_schema(item)
+        cls._validate_commit_message_length(item)
 
 
 class BaseCommitLogEntryModelValidator(BaseSnapshotMetadataModelValidator):


Test patch:
diff --git a/core/domain/base_model_validators_test.py b/core/domain/base_model_validators_test.py
--- a/core/domain/base_model_validators_test.py
+++ b/core/domain/base_model_validators_test.py
@@ -21,6 +21,7 @@
 
 import datetime
 
+from constants import constants
 from core import jobs_registry
 from core.domain import base_model_validators
 from core.domain import prod_validation_jobs_one_off
@@ -342,3 +343,23 @@ def test_error_raised_when_user_id_is_invalid(self):
             },
             mock_validator.errors
         )
+
+    def test_error_raised_when_commit_message_large(self):
+        model = MockCommitLogEntryModel(
+            id='mock-12345',
+            user_id=feconf.MIGRATION_BOT_USER_ID,
+            commit_cmds=[],
+            commit_message='a' * (constants.MAX_COMMIT_MESSAGE_LENGTH + 1))
+        model.update_timestamps()
+        mock_validator = MockCommitLogEntryModelValidator()
+        mock_validator.errors.clear()
+        mock_validator.validate(model)
+        self.assertDictContainsSubset(
+            {
+                'commit message check': [
+                    'Entity id mock-12345: '
+                    'Commit message larger than accepted length'
+                ]
+            },
+            mock_validator.errors
+        )
diff --git a/core/domain/prod_validators_test.py b/core/domain/prod_validators_test.py
--- a/core/domain/prod_validators_test.py
+++ b/core/domain/prod_validators_test.py
@@ -485,6 +485,21 @@ def test_maximum_of_ten_errors_are_emitted(self):
         for error in actual_error_list:
             assert (error in full_error_list), ('Extra error: %s' % error)
 
+    def test_model_with_invalid_commit_message_length(self):
+        self.model_instance_0.commit_message = 'a' * (
+            constants.MAX_COMMIT_MESSAGE_LENGTH + 1)
+        self.model_instance_0.update_timestamps()
+        self.model_instance_0.put()
+        expected_output = [
+            (
+                u'[u\'failed validation check for commit message check '
+                'of ExplorationSnapshotMetadataModel\', '
+                '[u\'Entity id 0-1: Commit message larger than '
+                'accepted length\']]'
+            ), u'[u\'fully-validated ExplorationSnapshotMetadataModel\', 2]']
+        self.run_job_and_check_output(
+            expected_output, sort=True, literal_eval=False)
+
 
 class ExplorationSnapshotContentModelValidatorTests(
         test_utils.AuditJobsTestBase):
@@ -1409,6 +1424,21 @@ def test_model_with_invalid_commit_cmd_schmea(self):
         self.run_job_and_check_output(
             expected_output, sort=True, literal_eval=False)
 
+    def test_model_with_invalid_commit_message_length(self):
+        self.model_instance_0.commit_message = 'a' * (
+            constants.MAX_COMMIT_MESSAGE_LENGTH + 1)
+        self.model_instance_0.update_timestamps()
+        self.model_instance_0.put()
+        expected_output = [
+            (
+                u'[u\'failed validation check for commit message check '
+                'of ExplorationCommitLogEntryModel\', '
+                '[u\'Entity id exploration-0-1: Commit message larger than '
+                'accepted length\']]'
+            ), u'[u\'fully-validated ExplorationCommitLogEntryModel\', 3]']
+        self.run_job_and_check_output(
+            expected_output, sort=True, literal_eval=False)
+
 
 class ExpSummaryModelValidatorTests(test_utils.AuditJobsTestBase):