From 14bb0b74afab0796d33bfabe48f23bfabe74e1ac Mon Sep 17 00:00:00 2001 From: Roman Donchenko Date: Mon, 23 Jan 2023 17:14:03 +0300 Subject: [PATCH] Fix a CI issue that causes unit tests to run against the wrong version of CVAT (#5612) There seems to be a bug somewhere in the Docker ecosystem (it's probably either Docker Compose, Docker Buildx or BuildKit) that causes `docker compose build` to ignore base images that are already present in the system, and instead fetch them from Docker Hub, if there's a custom Buildx builder configured. There's a bug report here: . This bug means that when the build pipeline builds the `cvat_ci` image, it's based on the latest release of `cvat/server` from Docker Hub instead of the version that we just built. Consequently, we run the unit tests against that release instead of the development version. Fortunately, we don't actually need to set up a Buildx builder in most jobs (including the `unit_testing` job), so just don't do that. Also, use `cvat/server:local` as the base image in `Dockerfile.ci`. This will prevent a similar bug from reoccurring in the future, since the `local` tag should never be uploaded to Docker Hub. --- .github/workflows/main.yml | 9 --------- Dockerfile.ci | 2 +- cvat/apps/engine/serializers.py | 9 ++++++++- cvat/apps/iam/tests/test_rest_api.py | 13 ++++++++++--- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4c7b2b5c..4d718074 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -135,9 +135,6 @@ jobs: with: python-version: '3.8' - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - name: Download CVAT server image uses: actions/download-artifact@v3 with: @@ -195,9 +192,6 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - name: Download CVAT server image uses: actions/download-artifact@v3 with: @@ -265,9 +259,6 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 - - uses: actions/setup-node@v3 with: node-version: '16.x' diff --git a/Dockerfile.ci b/Dockerfile.ci index ab01eb72..5bd67c12 100644 --- a/Dockerfile.ci +++ b/Dockerfile.ci @@ -1,4 +1,4 @@ -FROM cvat/server +FROM cvat/server:local ENV DJANGO_CONFIGURATION=testing USER root diff --git a/cvat/apps/engine/serializers.py b/cvat/apps/engine/serializers.py index 4256bfa9..2c871499 100644 --- a/cvat/apps/engine/serializers.py +++ b/cvat/apps/engine/serializers.py @@ -20,7 +20,7 @@ from cvat.apps.engine.cloud_provider import get_cloud_storage_instance, Credenti from cvat.apps.engine.log import slogger from cvat.apps.engine.utils import parse_specific_attributes -from drf_spectacular.utils import OpenApiExample, extend_schema_serializer +from drf_spectacular.utils import OpenApiExample, extend_schema_field, extend_schema_serializer class BasicUserSerializer(serializers.ModelSerializer): def validate(self, attrs): @@ -926,6 +926,13 @@ class FrameMetaSerializer(serializers.Serializer): name = serializers.CharField(max_length=1024) related_files = serializers.IntegerField() + # for compatibility with version 2.3.0 + has_related_context = serializers.SerializerMethodField() + + @extend_schema_field(serializers.BooleanField) + def get_has_related_context(self, obj: dict) -> bool: + return obj['related_files'] != 0 + class PluginsSerializer(serializers.Serializer): GIT_INTEGRATION = serializers.BooleanField() ANALYTICS = serializers.BooleanField() diff --git a/cvat/apps/iam/tests/test_rest_api.py b/cvat/apps/iam/tests/test_rest_api.py index 8a309d8a..acd899c1 100644 --- a/cvat/apps/iam/tests/test_rest_api.py +++ b/cvat/apps/iam/tests/test_rest_api.py @@ -150,7 +150,7 @@ class TestIamApi(APITestCase): ForceLogin(user=self.user, client=self.client): response = self.client.get(self.ENDPOINT_WITH_AUTH) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - self.assertEqual(response.json(), expected_reasons) + self.assertTrue(all([reason in str(response.content) for reason in expected_reasons])) def test_can_report_merged_denial_reasons(self): expected_reasons = [["hello", "world"], ["hi", "there"]] @@ -159,7 +159,14 @@ class TestIamApi(APITestCase): ForceLogin(user=self.user, client=self.client): response = self.client.get(self.ENDPOINT_WITH_AUTH) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - self.assertEqual(response.json(), list(itertools.chain.from_iterable(expected_reasons))) + self.assertTrue( + all( + [ + reason in str(response.content) + for reason in itertools.chain(*expected_reasons) + ] + ) + ) def test_can_allow_if_no_permission_matches(self): with self._mock_permissions(), ForceLogin(user=self.user, client=self.client): @@ -179,4 +186,4 @@ class TestIamApi(APITestCase): ForceLogin(user=self.user, client=self.client): response = self.client.get(self.ENDPOINT_WITH_AUTH) self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN) - self.assertEqual(response.json(), expected_reasons) + self.assertTrue(all([reason in str(response.content) for reason in expected_reasons]))