"""This file and its contents are licensed under the Apache License 2.0. Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
"""
import json
import os

import django
import pytest
from django.core.management import call_command
from django.shortcuts import reverse
from django.urls import get_resolver
from tasks.models import Annotation, Task

owner_statuses = {
    '/tasks/1000/label': {'get': 200, 'post': 200, 'put': 405, 'patch': 405, 'delete': 405},
    '/tasks/1000/delete': {'get': 302, 'post': 404, 'put': 405, 'patch': 405, 'delete': 405},
    '/tasks/1000/explore': {'get': 200, 'post': 200, 'put': 405, 'patch': 405, 'delete': 405},
    '/api/tasks/1000/cancel': {'get': 405, 'post': 200, 'put': 405, 'patch': 405, 'delete': 405},
    '/api/tasks/1000/annotations/': {'get': 200, 'post': 201, 'put': 405, 'patch': 405, 'delete': 405},
    '/api/tasks/1000/annotations/1000/': {'get': 200, 'post': 405, 'put': 200, 'patch': 200, 'delete': 204},
    '/api/tasks/1000/': {'get': 200, 'post': 405, 'put': 400, 'patch': 400, 'delete': 204},
    '/api/projects/1000/annotations/': {'get': 405, 'post': 405, 'put': 405, 'patch': 405, 'delete': 204},
    '/api/projects/1000/results/': {'get': 200, 'post': 405, 'put': 405, 'patch': 405, 'delete': 405},
    '/api/projects/1000/tasks/bulk/': {'get': 405, 'post': 400, 'put': 405, 'patch': 405, 'delete': 405},
    '/api/projects/1000/tasks/': {'get': 200, 'post': 415, 'put': 405, 'patch': 405, 'delete': 204},
    '/annotator/invites/1000': {'get': 403, 'post': 403, 'put': 403, 'patch': 403, 'delete': 403},
    '/annotator/projects/1000/editor': {'get': 403, 'post': 403, 'put': 403, 'patch': 403, 'delete': 403},
    '/annotator/projects/': {'get': 403, 'post': 403, 'put': 403, 'patch': 403, 'delete': 403},
    '/annotator/account/': {'get': 403, 'post': 403, 'put': 403, 'patch': 403, 'delete': 403},
    '/annotator/signup/': {'get': 403, 'post': 403, 'put': 403, 'patch': 403, 'delete': 403},
    '/annotator/login/': {'get': 403, 'post': 403, 'put': 403, 'patch': 403, 'delete': 403},
    '/logout': {'get': 302, 'post': 302, 'put': 302, 'patch': 302, 'delete': 302},
    '/api/': {'get': 200, 'post': 405, 'put': 405, 'patch': 405, 'delete': 405},
    '/api/projects/validate': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/api/projects/template': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/api/projects/1000/backends': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/api/projects/1000/backends/connections': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/api/projects/backends': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/api/projects/1000/predict': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/api/projects/1000/onboarding/1000': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/api/projects/1000/next': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/api/projects/1000/expert_instruction': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/api/projects/1000/': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/api/projects/': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/projects/upload-example/': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/projects/1000/ml': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/projects/1000/plots': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/projects/1000/experts': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/projects/1000/delete': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/projects/1000/duplicate': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/projects/1000/upload-example/': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/projects/1000/data': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/projects/1000/settings/edit-config': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/projects/1000/settings': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/projects/1000/': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/projects/render': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/projects/template/': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/projects/create/': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/projects/': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/business/not-approved': {'get': 200, 'post': 200, 'put': 200, 'patch': 200, 'delete': 200},
    '/business/stats': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/business/experts/list': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/user/account/': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/user/account/settings': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/user/signup/': {'get': 200, 'post': 200, 'put': 200, 'patch': 200, 'delete': 200},
    '/user/login/': {'get': 200, 'post': 200, 'put': 200, 'patch': 200, 'delete': 200},
    '/django-rq/queues/1000/1000/enqueue/': {'get': 302, 'post': 302, 'put': 302, 'patch': 302, 'delete': 302},
    '/django-rq/queues/1000/1000/requeue/': {'get': 302, 'post': 302, 'put': 302, 'patch': 302, 'delete': 302},
    '/django-rq/queues/actions/1000/': {'get': 302, 'post': 302, 'put': 302, 'patch': 302, 'delete': 302},
    '/django-rq/queues/1000/1000/delete/': {'get': 302, 'post': 302, 'put': 302, 'patch': 302, 'delete': 302},
    '/django-rq/queues/1000/1000/': {'get': 302, 'post': 302, 'put': 302, 'patch': 302, 'delete': 302},
    '/django-rq/queues/1000/requeue-all/': {'get': 302, 'post': 302, 'put': 302, 'patch': 302, 'delete': 302},
    '/django-rq/queues/1000/empty/': {'get': 302, 'post': 302, 'put': 302, 'patch': 302, 'delete': 302},
    '/django-rq/queues/1000/deferred/': {'get': 302, 'post': 302, 'put': 302, 'patch': 302, 'delete': 302},
    '/django-rq/queues/1000/started/': {'get': 302, 'post': 302, 'put': 302, 'patch': 302, 'delete': 302},
    '/django-rq/queues/1000/finished/': {'get': 302, 'post': 302, 'put': 302, 'patch': 302, 'delete': 302},
    '/django-rq/workers/1000/1000/': {'get': 302, 'post': 302, 'put': 302, 'patch': 302, 'delete': 302},
    '/django-rq/workers/1000/': {'get': 302, 'post': 302, 'put': 302, 'patch': 302, 'delete': 302},
    '/django-rq/queues/1000/': {'get': 302, 'post': 302, 'put': 302, 'patch': 302, 'delete': 302},
    '/django-rq/stats.json/': {'get': 200, 'post': 200, 'put': 200, 'patch': 200, 'delete': 200},
    '/django-rq/': {'get': 302, 'post': 302, 'put': 302, 'patch': 302, 'delete': 302},
}


other_business_statuses = {
    '/tasks/1000/label': {'get': 403, 'post': 403, 'put': 405, 'delete': 405},
    '/tasks/1000/delete': {'get': 403, 'post': 403, 'put': 405, 'delete': 405},
    '/tasks/1000/explore': {'get': 403, 'post': 403, 'put': 405, 'delete': 405},
    '/api/tasks/1000/cancel': {'get': 405, 'post': 403, 'put': 405, 'delete': 405},
    '/api/tasks/1000/annotations/': {'get': 403, 'post': 403, 'put': 405, 'delete': 405},
    '/api/tasks/1000/annotations/1000/': {'get': 403, 'post': 405, 'put': 403, 'delete': 403},
    '/api/tasks/1000/': {'get': 403, 'post': 405, 'put': 403, 'delete': 403},
    '/api/projects/1000/tasks/delete': {'get': 405, 'post': 405, 'put': 405, 'delete': 403},
    '/api/projects/1000/annotations/delete': {'get': 405, 'post': 405, 'put': 405, 'delete': 403},
    '/api/projects/1000/results/': {'get': 403, 'post': 405, 'put': 405, 'delete': 405},
    '/api/projects/1000/tasks/bulk/': {'get': 405, 'post': 403, 'put': 405, 'delete': 405},
    '/api/projects/1000/tasks/': {'get': 403, 'post': 415, 'put': 405, 'delete': 405},
    '/annotator/invites/1000': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/annotator/projects/1000/editor': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/annotator/projects/': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/annotator/account/': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/annotator/signup/': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/annotator/login/': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/logout': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/api/': {'get': 200, 'post': 405, 'put': 405, 'delete': 405},
    '/api/projects/validate': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/template': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/1000/backends': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/1000/predict': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/1000/onboarding/1000': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/1000/next': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/1000/expert_instruction': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/1000/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/upload-example/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/ml': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/plots': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/experts': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/delete': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/duplicate': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/upload-example/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/data/upload': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/data': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/settings/edit-config': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/settings': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/render': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/template/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/create/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/business/not-approved': {'get': 200, 'post': 200, 'put': 200, 'delete': 200},
    '/business/stats': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/business/experts/list': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/user/account/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/user/account/settings': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/user/signup/': {'get': 200, 'post': 200, 'put': 200, 'delete': 200},
    '/user/login/': {'get': 200, 'post': 200, 'put': 200, 'delete': 200},
    '/django-rq/queues/1000/1000/enqueue/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/1000/requeue/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/actions/1000/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/1000/delete/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/1000/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/requeue-all/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/empty/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/deferred/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/started/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/finished/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/workers/1000/1000/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/workers/1000/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/stats.json/': {'get': 200, 'post': 200, 'put': 200, 'delete': 200},
    '/django-rq/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
}


other_annotator_statuses = {
    '/tasks/1000/label': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/tasks/1000/delete': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/tasks/1000/explore': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/api/tasks/1000/cancel': {'get': 405, 'post': 403, 'put': 405, 'delete': 405},
    '/api/tasks/1000/annotations/': {'get': 403, 'post': 403, 'put': 405, 'delete': 405},
    '/api/tasks/1000/annotations/1000/': {'get': 403, 'post': 405, 'put': 403, 'delete': 403},
    '/api/tasks/1000/': {'get': 403, 'post': 405, 'put': 403, 'delete': 403},
    '/api/projects/1000/tasks/delete': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/api/projects/1000/annotations/delete': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/api/projects/1000/results/': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/api/projects/1000/tasks/bulk/': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/api/projects/1000/tasks/': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/annotator/invites/1000': {'get': 404, 'post': 404, 'put': 404, 'delete': 404},
    '/annotator/projects/1000/editor': {'get': 403, 'post': 403, 'put': 405, 'delete': 405},
    '/annotator/projects/': {'get': 200, 'post': 200, 'put': 405, 'delete': 405},
    '/annotator/account/': {'get': 200, 'post': 302, 'put': 405, 'delete': 405},
    '/annotator/signup/': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/annotator/login/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/logout': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/api/': {'get': 200, 'post': 405, 'put': 405, 'delete': 405},
    '/api/projects/validate': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/template': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/1000/backends': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/1000/predict': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/1000/onboarding/1000': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/1000/next': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/1000/expert_instruction': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/1000/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/upload-example/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/ml': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/plots': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/experts': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/delete': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/duplicate': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/upload-example/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/data/upload': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/data': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/settings/edit-config': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/settings': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/render': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/template/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/create/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/business/not-approved': {'get': 200, 'post': 200, 'put': 200, 'delete': 200},
    '/business/stats': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/business/experts/list': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/user/account/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/user/account/settings': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/user/signup/': {'get': 200, 'post': 200, 'put': 200, 'delete': 200},
    '/user/login/': {'get': 200, 'post': 200, 'put': 200, 'delete': 200},
    '/django-rq/queues/1000/1000/enqueue/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/1000/requeue/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/actions/1000/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/1000/delete/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/1000/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/requeue-all/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/empty/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/deferred/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/started/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/finished/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/workers/1000/1000/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/workers/1000/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/stats.json/': {'get': 200, 'post': 200, 'put': 200, 'delete': 200},
    '/django-rq/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
}


group_annotator_statuses = {
    '/tasks/1000/label': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/tasks/1000/delete': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/tasks/1000/explore': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/api/tasks/1000/cancel': {'get': 405, 'post': 403, 'put': 405, 'delete': 405},
    '/api/tasks/1000/annotations/': {'get': 403, 'post': 403, 'put': 405, 'delete': 405},
    '/api/tasks/1000/annotations/1000/': {'get': 403, 'post': 405, 'put': 403, 'delete': 403},
    '/api/tasks/1000/': {'get': 403, 'post': 405, 'put': 403, 'delete': 403},
    '/api/projects/1000/tasks/delete': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/api/projects/1000/annotations/delete': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/api/projects/1000/results/': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/api/projects/1000/tasks/bulk/': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/api/projects/1000/tasks/': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/annotator/invites/1000': {'get': 404, 'post': 404, 'put': 404, 'delete': 404},
    '/annotator/projects/1000/editor': {'get': 403, 'post': 403, 'put': 405, 'delete': 405},
    '/annotator/projects/': {'get': 200, 'post': 200, 'put': 405, 'delete': 405},
    '/annotator/account/': {'get': 200, 'post': 302, 'put': 405, 'delete': 405},
    '/annotator/signup/': {'get': 403, 'post': 403, 'put': 403, 'delete': 403},
    '/annotator/login/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/logout': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/api/': {'get': 200, 'post': 405, 'put': 405, 'delete': 405},
    '/api/projects/validate': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/template': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/1000/backends': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/1000/predict': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/1000/onboarding/1000': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/1000/next': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/1000/expert_instruction': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/api/projects/1000/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/upload-example/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/ml': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/plots': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/experts': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/delete': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/duplicate': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/upload-example/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/data/upload': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/data': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/settings/edit-config': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/settings': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/1000/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/render': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/template/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/create/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/projects/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/business/not-approved': {'get': 200, 'post': 200, 'put': 200, 'delete': 200},
    '/business/stats': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/business/experts/list': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/user/account/': {'get': 401, 'post': 401, 'put': 401, 'delete': 401},
    '/user/account/settings': {'get': 401, 'post': 401, 'put': 401, 'patch': 401, 'delete': 401},
    '/user/signup/': {'get': 200, 'post': 200, 'put': 200, 'delete': 200},
    '/user/login/': {'get': 200, 'post': 200, 'put': 200, 'delete': 200},
    '/django-rq/queues/1000/1000/enqueue/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/1000/requeue/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/actions/1000/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/1000/delete/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/1000/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/requeue-all/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/empty/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/deferred/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/started/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/finished/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/workers/1000/1000/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/workers/1000/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/queues/1000/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
    '/django-rq/stats.json/': {'get': 200, 'post': 200, 'put': 200, 'delete': 200},
    '/django-rq/': {'get': 302, 'post': 302, 'put': 302, 'delete': 302},
}


def build_urls(project_id, task_id, annotation_id):
    """Get all the ulrs from django"""
    urls = []
    exclude_urls = {'schema-json', 'schema-swagger-ui', 'schema-redoc'}
    resolver = get_resolver(None).reverse_dict
    for url_name in resolver:
        if isinstance(url_name, str) and url_name not in exclude_urls:
            keys = resolver[url_name][0][0][1]
            kwargs = {}
            for key in keys:
                if 'pk' in key:
                    kwargs[key] = 1000  # for example user_pk or project_pk will be 1000

                if key in ['pk', 'step_pk', 'job_id', 'queue_index', 'scheduler_index']:
                    kwargs[key] = 1000
                elif key in ['token', 'uidb64']:
                    kwargs[key] = 1000
                elif key in ['key']:
                    kwargs[key] = '1000'
                elif key == 'sub_path':
                    kwargs[key] = 'settings'  # default sub_path for user account

                # we need to use really existing project/task/annotation ids from fixture
                if key == 'project_id' or key == 'project_pk':
                    kwargs[key] = project_id
                elif key == 'task_id':
                    kwargs[key] = task_id
                elif key == 'annotation_id':
                    kwargs[key] = annotation_id
                elif 'id' in key:
                    kwargs[key] = 1

                if url_name == 'password_reset_confirm':
                    kwargs['token'] = '1000-1000'
                    kwargs['uidb64'] = '1000'
            try:
                url = reverse(url_name, kwargs=kwargs)
            except django.urls.exceptions.NoReverseMatch as e:
                print(
                    f'\n\n ---> Could not find "{url_name}" with django reverse and kwargs "{kwargs}".\n'
                    f'Probably some kwarg is absent\n\n'
                )
                raise e

            exclude = ['/password-reset/complete/', '/password-reset/']
            add = True
            for exc in exclude:
                if url.startswith(exc):
                    add = False

            if add:
                urls.append(url)

    return urls


def restore_objects(project):
    """Create task and annotation for URL tests"""
    # task_db, annotation_db = None, None

    if project.pk != 1000:
        project.pk = 1000
        project.title += '2'
        project.save()
    try:
        task_db = Task.objects.get(pk=1000)
    except Task.DoesNotExist:
        task_db = Task()
        task_db.data = {'data': {'image': 'kittens.jpg'}}
        task_db.project = project
        task_db.id = 1000  # we need to use id 1000 to avoid db last start
        task_db.save()

    try:
        annotation_db = Annotation.objects.get(pk=1000)
    except Annotation.DoesNotExist:
        task_db = Task.objects.get(pk=1000)
        annotation_db = Annotation()
        annotation = [{'from_name': 'some', 'to_name': 'x', 'type': 'none', 'value': {'none': ['Opossum']}}]
        annotation_db.result = annotation
        annotation_db.id = 1000  # we need to use id 1000 to avoid db last start
        annotation_db.task = task_db
        annotation_db.save()

    return task_db, annotation_db


def check_urls(urls, runner, match_statuses, project):
    statuses = {}
    for url in urls:
        print('-->', url)
        status = {}
        restore_objects(project)

        r = runner.get(url)
        status['get'] = r.status_code

        r = runner.post(url)
        status['post'] = r.status_code

        r = runner.put(url)
        status['put'] = r.status_code

        r = runner.patch(url)
        status['patch'] = r.status_code

        r = runner.delete(url)
        status['delete'] = r.status_code

        # assert url in match_statuses, '\nNew URL found, please check statuses and add \n\n' \
        #                              + url + ': ' + str(status) + \
        #                              '\n\nto dict \n\n' + runner.statuses_name + '\n'

        statuses[url] = status
        # assert match_statuses[url] == status, f'Expected statuses mismatch: "{url}"'

    # print(statuses)  # use this to collect urls -> statuses dict


def run(owner, runner):
    """Get all urls from Django and GET/POST/PUT/DELETE them"""
    owner.task_db, owner.annotation_db = restore_objects(owner.project)
    urls = build_urls(owner.project.id, owner.task_db.id, owner.annotation_db.id)

    check_urls(urls, runner, runner.statuses, owner.project)


@pytest.mark.django_db
def test_all_urls_owner(setup_project_choices):
    runner = owner = setup_project_choices
    runner.statuses = owner_statuses
    runner.statuses_name = 'owner_statuses'
    run(owner, runner)


@pytest.mark.django_db
def test_all_urls_other_business(setup_project_choices, business_client):
    business_client.statuses = other_business_statuses
    business_client.statuses_name = 'other_business_statuses'
    run(setup_project_choices, business_client)


@pytest.mark.django_db
def test_urls_mismatch_with_registered(tmpdir):
    from core.utils.io import find_file

    all_urls_file = find_file('all_urls.json')
    with open(all_urls_file) as f:
        all_urls = json.load(f)

    instruction = (
        f'If you created, removed or updated URLs, run the following command:\n./manage.py show_urls --format pretty-json > new_urls.json\n'
        f'After creation, you should verify and correct mismatched data by updating {all_urls_file}.'
    )

    f = tmpdir.mkdir('subdir').join('show_urls.json')
    call_command('show_urls', format='pretty-json', stdout=f)
    filename = os.path.join(f.dirname, f.basename)
    with open(filename) as f1:
        all_current_urls = json.load(f1)

    all_urls = sorted(str((d['url'], d['name'])) for d in all_urls)
    all_current_urls = sorted(str((d['url'], d['name'])) for d in all_current_urls)

    if len(all_urls) > len(all_current_urls):
        urls_removed = '\n'.join(set(all_urls) - set(all_current_urls))
        assert False, (
            f'URLs number mismatch: {len(all_urls)} expected but new version contains {len(all_current_urls)}. '
            f'URLs removed:\n{urls_removed}.\n{instruction}'
        )
    elif len(all_urls) < len(all_current_urls):
        urls_added = '\n'.join(set(all_current_urls) - set(all_urls))
        assert False, (
            f'URLs number mismatch: {len(all_urls)} expected but new version contains {len(all_current_urls)}. '
            f'New URLs added:\n{urls_added}.\n{instruction}'
        )

    for url, new_url in zip(all_urls, all_current_urls):
        assert url == new_url, f'URL name mismatch found. {instruction}'
