# Copyright 2021-2022 The Debusine Developers
# See the AUTHORS file at the top-level directory of this distribution
#
# This file is part of Debusine. It is subject to the license terms
# in the LICENSE file found in the top-level directory of this
# distribution. No part of Debusine, including this file, may be copied,
# modified, propagated, or distributed except according to the terms
# contained in the LICENSE file.

"""Tests for serializers."""

from datetime import datetime

from django.test import TestCase

import pytz

from rest_framework.exceptions import ErrorDetail

from debusine.db.models import Token, WorkRequest, Worker
from debusine.server.serializers import (
    WorkRequestCompletedSerializer,
    WorkRequestSerializer,
    WorkerRegisterSerializer,
)


class WorkRequestSerializerTests(TestCase):
    """Tests for WorkRequestSerializer."""

    def setUp(self):
        """Initialize test."""
        token = Token.objects.create()

        worker = Worker.objects.create_with_fqdn('worker.lan', token)

        self.work_request = WorkRequest(
            started_at=datetime(2022, 2, 20, 15, 19, 1, 158424, pytz.UTC),
            completed_at=datetime(2022, 2, 20, 16, 2, 3, 558425, pytz.UTC),
            status=WorkRequest.Statuses.COMPLETED,
            result=WorkRequest.Results.SUCCESS,
            worker=worker,
            task_name='sbuild',
            task_data={'arch': 'x64'},
        )

        self.work_request_serializer = WorkRequestSerializer(self.work_request)

    def test_expected_fields(self):
        """Serializer returns the expected fields."""
        self.assertEqual(
            set(self.work_request_serializer.data.keys()),
            {
                'id',
                'status',
                'worker',
                'created_at',
                'started_at',
                'completed_at',
                'duration',
                'task_name',
                'task_data',
                'result',
            },
        )

    def assert_is_valid(
        self, data, only_fields, is_valid_expected, errors=None
    ):
        """Validate data using only_fields and expects is_valid_expected."""
        work_request_serializer = WorkRequestSerializer(
            data=data, only_fields=only_fields
        )
        self.assertEqual(work_request_serializer.is_valid(), is_valid_expected)

        if errors is not None:
            self.assertEqual(work_request_serializer.errors, errors)

    def test_validate_only_fields_invalid(self):
        """Use only_fields with an extra field."""
        data = {
            'task_name': 'sbuild',
            'task_data': {'foo': 'bar'},
            'unwanted_field': 'for testing',
            'unwanted_field2': 'for testing',
        }
        errors = {
            'non_field_errors': [
                ErrorDetail(
                    string='Invalid fields: unwanted_field, unwanted_field2',
                    code='invalid',
                )
            ]
        }
        self.assert_is_valid(data, ['task_name', 'task_data'], False, errors)

    def test_validate_only_fields_valid(self):
        """Use only_fields with an extra field in data."""
        data = {'task_name': 'sbuild', 'task_data': {'foo': 'bar'}}
        self.assert_is_valid(data, ['task_name', 'task_data'], True)

    def test_validate_without_only_fields(self):
        """is_valid() return True: not using only_fields."""
        data = {'task_name': 'sbuild'}
        self.assert_is_valid(data, None, True)


class WorkerRegisterSerializerTests(TestCase):
    """Test for WorkerRegisterSerializer class."""

    def test_expected_fields(self):
        """Expected fields are defined in the serializer."""
        worker_register_serializer = WorkerRegisterSerializer()
        data = worker_register_serializer.data

        self.assertSetEqual(set(data.keys()), {'token', 'fqdn'})


class WorkRequestCompletedSerializerTests(TestCase):
    """Test for WorkRequestCompletedSerializer class."""

    def test_accept_success(self):
        """Serializer accept {"result": "success" }."""
        work_request_completed_serializer = WorkRequestCompletedSerializer(
            data={'result': 'success'}
        )
        self.assertTrue(work_request_completed_serializer.is_valid())
        self.assertEqual(
            work_request_completed_serializer.validated_data['result'],
            'success',
        )

    def test_not_accept_unknown_result(self):
        """Serializer does not accept unrecognised result."""
        work_request_completed_serializer = WorkRequestCompletedSerializer(
            data={'result': 'something'}
        )
        self.assertFalse(work_request_completed_serializer.is_valid())
