Repository: django-haystack/django-haystack

Issue:
Need Help: GitHub Actions tests are failing
# Fix container networking in our GitHub Actions environment.

Our GitHub Actions tests have consistently failed since they were set up.  Please help us to get effective tests that pass.
* https://github.com/django-haystack/django-haystack/actions/workflows/test.yml

This is caused by the issues in:
* #1921 
* #1929


Discussion:

Resolving patch:
diff --git a/haystack/admin.py b/haystack/admin.py
--- a/haystack/admin.py
+++ b/haystack/admin.py
@@ -1,3 +1,4 @@
+from django import VERSION as django_version
 from django.contrib.admin.options import ModelAdmin, csrf_protect_m
 from django.contrib.admin.views.main import SEARCH_VAR, ChangeList
 from django.core.exceptions import PermissionDenied
@@ -15,7 +16,10 @@
 class SearchChangeList(ChangeList):
     def __init__(self, **kwargs):
         self.haystack_connection = kwargs.pop("haystack_connection", DEFAULT_ALIAS)
-        super().__init__(**kwargs)
+        super_kwargs = kwargs
+        if django_version[0] >= 4:
+            super_kwargs["search_help_text"] = "Search..."
+        super().__init__(**super_kwargs)
 
     def get_results(self, request):
         if SEARCH_VAR not in request.GET:


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -56,6 +56,8 @@ jobs:
           python-version: ${{ matrix.python-version }}
       - name: Install system dependencies
         run: sudo apt install --no-install-recommends -y gdal-bin
+      - name: Setup solr test server in Docker
+        run: bash test_haystack/solr_tests/server/setup-solr-test-server-in-docker.sh
       - name: Install dependencies
         run: |
           python -m pip install --upgrade pip setuptools wheel
diff --git a/test_haystack/solr_tests/server/setup-solr-test-server-in-docker.sh b/test_haystack/solr_tests/server/setup-solr-test-server-in-docker.sh
new file mode 100644
--- /dev/null
+++ b/test_haystack/solr_tests/server/setup-solr-test-server-in-docker.sh
@@ -0,0 +1,15 @@
+# figure out the solr container ID
+SOLR_CONTAINER=`docker ps -f ancestor=solr:6 --format '{{.ID}}'`
+
+LOCAL_CONFDIR=./test_haystack/solr_tests/server/confdir
+CONTAINER_CONFDIR=/opt/solr/server/solr/collection1/conf
+
+# set up a solr core
+docker exec $SOLR_CONTAINER ./bin/solr create -c collection1 -p 8983 -n basic_config
+# copy the testing schema to the collection and fix permissions
+docker cp $LOCAL_CONFDIR/solrconfig.xml $SOLR_CONTAINER:$CONTAINER_CONFDIR/solrconfig.xml
+docker cp $LOCAL_CONFDIR/schema.xml $SOLR_CONTAINER:$CONTAINER_CONFDIR/schema.xml
+docker exec $SOLR_CONTAINER mv $CONTAINER_CONFDIR/managed-schema $CONTAINER_CONFDIR/managed-schema.old
+docker exec -u root $SOLR_CONTAINER chown -R solr:solr /opt/solr/server/solr/collection1
+# reload the solr core
+curl "http://localhost:9001/solr/admin/cores?action=RELOAD&core=collection1"
diff --git a/test_haystack/solr_tests/test_solr_backend.py b/test_haystack/solr_tests/test_solr_backend.py
--- a/test_haystack/solr_tests/test_solr_backend.py
+++ b/test_haystack/solr_tests/test_solr_backend.py
@@ -420,7 +420,7 @@ def test_search(self):
                     "results"
                 ]
             ],
-            ["<i>Indexed</i>!\n1", "<i>Indexed</i>!\n2", "<i>Indexed</i>!\n3"],
+            ["<i>Indexed</i>!\n1\n", "<i>Indexed</i>!\n2\n", "<i>Indexed</i>!\n3\n"],
         )
 
         # full-form highlighting options
diff --git a/test_haystack/solr_tests/test_solr_management_commands.py b/test_haystack/solr_tests/test_solr_management_commands.py
--- a/test_haystack/solr_tests/test_solr_management_commands.py
+++ b/test_haystack/solr_tests/test_solr_management_commands.py
@@ -1,5 +1,7 @@
 import datetime
 import os
+import shutil
+import tempfile
 from io import StringIO
 from tempfile import mkdtemp
 from unittest.mock import patch
@@ -218,6 +220,9 @@ def test_build_schema(self):
         oldui = connections["solr"].get_unified_index()
         oldurl = settings.HAYSTACK_CONNECTIONS["solr"]["URL"]
 
+        conf_dir = tempfile.mkdtemp()
+        with open(os.path.join(conf_dir, "managed-schema"), "w+") as fp:
+            pass
         try:
             needle = "Th3S3cr3tK3y"
             constants.DOCUMENT_FIELD = (
@@ -234,10 +239,6 @@ def test_build_schema(self):
 
             rendered_file = StringIO()
 
-            script_dir = os.path.realpath(os.path.dirname(__file__))
-            conf_dir = os.path.join(
-                script_dir, "server", "solr", "server", "solr", "mgmnt", "conf"
-            )
             schema_file = os.path.join(conf_dir, "schema.xml")
             solrconfig_file = os.path.join(conf_dir, "solrconfig.xml")
 
@@ -261,16 +262,23 @@ def test_build_schema(self):
                 os.path.isfile(os.path.join(conf_dir, "managed-schema.old"))
             )
 
-            call_command("build_solr_schema", using="solr", reload_core=True)
+            with patch(
+                "haystack.management.commands.build_solr_schema.requests.get"
+            ) as mock_request:
+                call_command("build_solr_schema", using="solr", reload_core=True)
 
-            os.rename(schema_file, "%s.bak" % schema_file)
-            self.assertRaises(
-                CommandError,
-                call_command,
-                "build_solr_schema",
-                using="solr",
-                reload_core=True,
-            )
+            with patch(
+                "haystack.management.commands.build_solr_schema.requests.get"
+            ) as mock_request:
+                mock_request.return_value.ok = False
+
+                self.assertRaises(
+                    CommandError,
+                    call_command,
+                    "build_solr_schema",
+                    using="solr",
+                    reload_core=True,
+                )
 
             call_command("build_solr_schema", using="solr", filename=schema_file)
             with open(schema_file) as s:
@@ -280,6 +288,7 @@ def test_build_schema(self):
             constants.DOCUMENT_FIELD = oldhdf
             connections["solr"]._index = oldui
             settings.HAYSTACK_CONNECTIONS["solr"]["URL"] = oldurl
+            shutil.rmtree(conf_dir, ignore_errors=True)
 
 
 class AppModelManagementCommandTestCase(TestCase):
diff --git a/test_haystack/spatial/test_spatial.py b/test_haystack/spatial/test_spatial.py
--- a/test_haystack/spatial/test_spatial.py
+++ b/test_haystack/spatial/test_spatial.py
@@ -106,6 +106,7 @@ def setUp(self):
 
         super().setUp()
         self.ui = connections[self.using].get_unified_index()
+        self.ui.reset()
         self.checkindex = self.ui.get_index(Checkin)
         self.checkindex.reindex(using=self.using)
         self.sqs = SearchQuerySet().using(self.using)
diff --git a/test_haystack/test_management_commands.py b/test_haystack/test_management_commands.py
--- a/test_haystack/test_management_commands.py
+++ b/test_haystack/test_management_commands.py
@@ -77,8 +77,8 @@ def test_rebuild_index(self, mock_handle_clear, mock_handle_update):
         self.assertTrue(mock_handle_clear.called)
         self.assertTrue(mock_handle_update.called)
 
-    @patch("haystack.management.commands.update_index.Command.handle")
-    @patch("haystack.management.commands.clear_index.Command.handle")
+    @patch("haystack.management.commands.update_index.Command.handle", return_value="")
+    @patch("haystack.management.commands.clear_index.Command.handle", return_value="")
     def test_rebuild_index_nocommit(self, *mocks):
         call_command("rebuild_index", interactive=False, commit=False)
 
diff --git a/test_haystack/test_query.py b/test_haystack/test_query.py
--- a/test_haystack/test_query.py
+++ b/test_haystack/test_query.py
@@ -95,6 +95,12 @@ def test_simple_nesting(self):
 class BaseSearchQueryTestCase(TestCase):
     fixtures = ["base_data.json", "bulk_data.json"]
 
+    @classmethod
+    def setUpClass(cls):
+        for connection in connections.all():
+            connection.get_unified_index().reset()
+        super().setUpClass()
+
     def setUp(self):
         super().setUp()
         self.bsq = BaseSearchQuery()