Repository: translate/pootle

Issue:
Creating a new language should calculate stats
When creating a fresh language we are not currently calculating statistics for it. Needs to be fixed for 2.6.



Discussion:
I'm not sure how to do that by the way, will need help with it.

I think that the issue is "when we add a new language to an existing project we are not calculating the statistics".

After trying several possible fixes I gave up, so added a warning in the release notes (see 41eb0df3). We can revisit this when we have a working task queue on place and we have fixed all the transaction related issues.

@unho don't this was exactly what we concluded in our chat yesterday.  We'll solve this one directly, the warning about going out of sink is needed though.

The fix proposed in f2e94a1f seems to hang Travis build.

... hangs Travis build because counts are triggering in setup as we add languages to the default projects.

In the future the way to calculate the stats would be using a task in the queue. But now these are the proposed ways to overcome current issues with fix in https://github.com/translate/pootle/commit/f2e94a1f232294bcd7584967a33135f675839ca7:
- Calculate stats on first visit to language instead
- Avoid calculating stats when adding if we are running setup using an environment variable
- Add an action to allow calculating stats on demand

Each choice has its own drawbacks. Calculate on first visit or using an action can freeze the UI. Using a variable needs to add code to set, unset and check for existence of the variable.

@julen Is this an issue on the new master?

@julen Is this an issue on the new master?

i believe this may have already been fixed in #4218 

This is a good candidate to add a test for it.

ref #4231 

This is not an issue after we've forbidden to add new languages for projects without templates in 
3f157455.
If we add new language for a project with templates, stats will be filled properly (fixed in 82295d6).
We can close this issue, but tests are very needed here.


Resolving patch:
diff --git a/pootle/apps/pootle_translationproject/models.py b/pootle/apps/pootle_translationproject/models.py
--- a/pootle/apps/pootle_translationproject/models.py
+++ b/pootle/apps/pootle_translationproject/models.py
@@ -287,6 +287,9 @@ def save(self, *args, **kwargs):
                     init_store_from_template(self, template_store)
 
             self.scan_files()
+            # If this TP has no stores cache should be updated forcibly.
+            if self.stores.live().count() == 0:
+                self.update_all_cache()
 
             # Create units from disk store
             for store in self.stores.live().iterator():
diff --git a/pootle_pytest/fixtures/site.py b/pootle_pytest/fixtures/site.py
--- a/pootle_pytest/fixtures/site.py
+++ b/pootle_pytest/fixtures/site.py
@@ -44,11 +44,11 @@ def site_matrix_with_subdirs(site_matrix):
 
 
 @pytest.fixture
-def site_matrix(request, system, settings):
+def site_root(request, system, settings):
 
     from pootle_pytest.factories import (
-        ProjectFactory, DirectoryFactory, LanguageFactory,
-        TranslationProjectFactory)
+        ProjectFactory, DirectoryFactory, LanguageFactory
+    )
 
     from pootle_app.models import Directory
 
@@ -68,11 +68,6 @@ def site_matrix(request, system, settings):
         # add 2 projects
         project = ProjectFactory(source_language=languages[0])
 
-        for language in languages:
-            # add a TP to the project for each language
-            tp = TranslationProjectFactory(project=project, language=language)
-            _add_stores(tp)
-
     def _teardown():
         if "root" in Directory.objects.__dict__:
             del Directory.objects.__dict__['root']
@@ -86,3 +81,16 @@ def _teardown():
                         settings.POOTLE_TRANSLATION_DIRECTORY, trans_dir))
 
     request.addfinalizer(_teardown)
+
+
+@pytest.fixture
+def site_matrix(site_root):
+    from pootle_project.models import Project
+    from pootle_language.models import Language
+    from pootle_pytest.factories import TranslationProjectFactory
+
+    for project in Project.objects.all():
+        for language in Language.objects.all():
+            # add a TP to the project for each language
+            tp = TranslationProjectFactory(project=project, language=language)
+            _add_stores(tp)
diff --git a/pootle_pytest/plugin.py b/pootle_pytest/plugin.py
--- a/pootle_pytest/plugin.py
+++ b/pootle_pytest/plugin.py
@@ -37,7 +37,7 @@
     FILE_IMPORT_FAIL_TESTS,
     file_import_failure, ts_directory, en_tutorial_ts)
 from fixtures.revision import revision
-from fixtures.site import site_matrix, site_matrix_with_subdirs
+from fixtures.site import site_matrix, site_matrix_with_subdirs, site_root
 from fixtures.views import admin_client
 
 from fixtures.core.utils.wordcount import WORDCOUNT_TESTS
@@ -74,4 +74,5 @@ def pytest_generate_tests(metafunc):
     'english_tutorial', 'french_tutorial', 'italian_tutorial',
     'russian_tutorial', 'spanish_tutorial', 'templates_tutorial',
     'delete_pattern', 'en_tutorial_ts', 'file_import_failure', 'ts_directory',
-    'revision', 'admin_client', 'site_matrix', 'site_matrix_with_subdirs')
+    'revision', 'admin_client', 'site_matrix', 'site_matrix_with_subdirs',
+    'site_root',)


Test patch:
diff --git a/tests/models/translationproject.py b/tests/models/translationproject.py
--- a/tests/models/translationproject.py
+++ b/tests/models/translationproject.py
@@ -27,14 +27,6 @@ def test_tp_create_fail(tutorial, english):
         TranslationProject.objects.create(project=tutorial, language=english)
 
 
-@pytest.mark.django_db
-def test_tp_create_no_files(tutorial, fish):
-    # There are no files on disk so TP was not automagically created and there
-    # are no templates loaded
-    tp = TranslationProject.objects.create(project=tutorial, language=fish)
-    assert list(tp.stores.all()) == []
-
-
 def _test_tp_stores_match(tp1, tp2):
     # For testing tp creation from templates
     assert tp1.stores.count() == tp2.stores.count()
@@ -79,3 +71,40 @@ def test_tp_create_with_files(tutorial, english, klingon, settings):
     TranslationProject.objects.create(project=tutorial, language=klingon)
 
     shutil.rmtree(os.path.join(trans_dir, "tutorial/kl"))
+
+
+@pytest.mark.django_db
+def test_tp_empty_stats(site_root):
+    from pootle_project.models import Project
+    from pootle_language.models import Language
+    from pootle_translationproject.models import TranslationProject
+
+    project = Project.objects.first()
+    language = Language.objects.first()
+
+    tp, created = TranslationProject.objects.get_or_create(language=language,
+                                                           project=project)
+
+    # There are no files on disk so TP was not automagically created and there
+    # are no templates loaded
+    assert list(tp.stores.all()) == []
+
+    # Check if zero stats is calculated and available
+    stats = tp.get_stats()
+    assert stats['total'] == 0
+    assert stats['translated'] == 0
+    assert stats['fuzzy'] == 0
+    assert stats['suggestions'] == 0
+    assert stats['critical'] == 0
+
+
+@pytest.mark.django_db
+def test_tp_stats_created_from_template(tutorial, fish, templates):
+    tp = TranslationProject.objects.create(project=tutorial, language=fish)
+    assert tp.stores.all().count() == 1
+    stats = tp.get_stats()
+    assert stats['total'] == 2  # there are 2 words in test template
+    assert stats['translated'] == 0
+    assert stats['fuzzy'] == 0
+    assert stats['suggestions'] == 0
+    assert stats['critical'] == 0