nautobot 3.0.0a2__py3-none-any.whl → 3.0.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nautobot/apps/choices.py +4 -2
- nautobot/apps/filters.py +7 -9
- nautobot/apps/models.py +2 -2
- nautobot/apps/ui.py +13 -1
- nautobot/apps/utils.py +8 -0
- nautobot/circuits/filters.py +3 -2
- nautobot/circuits/navigation.py +3 -2
- nautobot/circuits/templates/circuits/circuit_create.html +3 -3
- nautobot/circuits/templates/circuits/circuittermination_create.html +9 -24
- nautobot/circuits/templates/circuits/inc/circuit_termination_cable_fragment.html +6 -6
- nautobot/circuits/templates/circuits/inc/speed_widget.html +12 -12
- nautobot/circuits/tests/integration/test_circuit.py +10 -13
- nautobot/circuits/tests/integration/test_circuits_bulk_operations.py +0 -3
- nautobot/circuits/views.py +6 -2
- nautobot/cloud/filters.py +1 -1
- nautobot/cloud/navigation.py +3 -2
- nautobot/core/api/schema.py +1 -1
- nautobot/core/api/serializers.py +6 -1
- nautobot/core/api/urls.py +2 -0
- nautobot/core/api/views.py +12 -0
- nautobot/core/apps/__init__.py +11 -10
- nautobot/core/celery/__init__.py +3 -5
- nautobot/core/checks.py +46 -0
- nautobot/core/choices.py +1 -1
- nautobot/core/cli/bootstrap_v3_to_v5.py +105 -13
- nautobot/core/cli/migrate_deprecated_templates.py +227 -0
- nautobot/core/constants.py +3 -0
- nautobot/core/context_processors.py +9 -1
- nautobot/core/filters.py +4 -0
- nautobot/core/forms/__init__.py +2 -0
- nautobot/core/forms/forms.py +1 -1
- nautobot/core/forms/widgets.py +21 -2
- nautobot/core/jobs/__init__.py +62 -3
- nautobot/core/jobs/groups.py +31 -1
- nautobot/core/management/commands/generate_test_data.py +28 -9
- nautobot/core/models/__init__.py +11 -0
- nautobot/core/models/generics.py +9 -1
- nautobot/core/models/tree_queries.py +10 -5
- nautobot/core/models/utils.py +1 -1
- nautobot/core/settings.py +35 -19
- nautobot/core/settings.yaml +17 -33
- nautobot/core/signals.py +12 -1
- nautobot/core/tables.py +13 -6
- nautobot/core/templates/40x.html +1 -1
- nautobot/core/templates/500.html +2 -2
- nautobot/core/templates/admin/base.html +1 -2
- nautobot/core/templates/admin/change_list.html +9 -12
- nautobot/core/templates/admin/config/config.html +12 -12
- nautobot/core/templates/admin/index.html +3 -3
- nautobot/core/templates/base_django.html +1 -2
- nautobot/core/templates/buttons/export.html +1 -1
- nautobot/core/templates/components/button/dropdown.html +5 -3
- nautobot/core/templates/components/panel/body_wrapper_generic_table.html +1 -1
- nautobot/core/templates/components/panel/header_extra_content_table.html +1 -1
- nautobot/core/templates/components/panel/panel.html +3 -3
- nautobot/core/templates/components/tab/content_wrapper.html +6 -7
- nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +1 -1
- nautobot/core/templates/echarts/echarts.html +22 -9
- nautobot/core/templates/generic/object_bulk_add_component.html +2 -1
- nautobot/core/templates/generic/object_bulk_create.html +6 -5
- nautobot/core/templates/generic/object_bulk_delete.html +1 -1
- nautobot/core/templates/generic/object_bulk_destroy.html +3 -3
- nautobot/core/templates/generic/object_bulk_edit.html +1 -1
- nautobot/core/templates/generic/object_bulk_import.html +1 -1
- nautobot/core/templates/generic/object_bulk_remove.html +2 -2
- nautobot/core/templates/generic/object_bulk_update.html +5 -4
- nautobot/core/templates/generic/object_create.html +5 -4
- nautobot/core/templates/generic/object_delete.html +1 -1
- nautobot/core/templates/generic/object_detail.html +1 -1
- nautobot/core/templates/generic/object_edit.html +1 -1
- nautobot/core/templates/generic/object_import.html +2 -1
- nautobot/core/templates/generic/object_list.html +12 -4
- nautobot/core/templates/generic/object_notes.html +5 -3
- nautobot/core/templates/generic/object_retrieve.html +4 -5
- nautobot/core/templates/graphene/graphiql.html +7 -8
- nautobot/core/templates/home.html +1 -1
- nautobot/core/templates/import_success.html +2 -1
- nautobot/core/templates/inc/computed_fields/panel_data.html +1 -1
- nautobot/core/templates/inc/created_updated.html +7 -3
- nautobot/core/templates/inc/custom_fields/panel_data.html +1 -1
- nautobot/core/templates/inc/footer.html +3 -1
- nautobot/core/templates/inc/form_static_field.html +6 -0
- nautobot/core/templates/inc/header.html +11 -1
- nautobot/core/templates/inc/image_attachments.html +2 -1
- nautobot/core/templates/inc/media.html +14 -0
- nautobot/core/templates/inc/nav_menu.html +3 -9
- nautobot/core/templates/inc/object_details_advanced_panel.html +2 -2
- nautobot/core/templates/inc/search_panel.html +4 -4
- nautobot/core/templates/login.html +4 -2
- nautobot/core/templates/nautobot_config.py.j2 +6 -11
- nautobot/core/templates/redoc_ui.html +7 -0
- nautobot/core/templates/rest_framework/api.html +103 -2
- nautobot/core/templates/search.html +1 -1
- nautobot/core/templates/swagger_ui.html +17 -3
- nautobot/core/templates/system_jobs/import_objects.html +1 -2
- nautobot/core/templates/utilities/confirmation_form.html +2 -2
- nautobot/core/templates/utilities/obj_table.html +10 -2
- nautobot/core/templates/utilities/render_field.html +7 -7
- nautobot/core/templates/utilities/render_jinja2.html +2 -2
- nautobot/core/templates/utilities/templatetags/filter_form_drawer.html +37 -4
- nautobot/core/templates/utilities/theme_preview.html +19 -3
- nautobot/core/templates/widgets/number_input_with_choices.html +44 -0
- nautobot/core/templates/widgets/selectwithdisabled_option.html +3 -1
- nautobot/core/templatetags/helpers.py +76 -18
- nautobot/core/testing/api.py +68 -9
- nautobot/core/testing/filters.py +0 -23
- nautobot/core/testing/integration.py +41 -17
- nautobot/core/testing/mixins.py +2 -0
- nautobot/core/testing/utils.py +18 -4
- nautobot/core/testing/views.py +104 -13
- nautobot/core/tests/integration/test_app_home.py +34 -30
- nautobot/core/tests/integration/test_app_navbar.py +3 -0
- nautobot/core/tests/integration/test_filters.py +48 -11
- nautobot/core/tests/integration/test_theme.py +22 -21
- nautobot/core/tests/nautobot_config.py +3 -0
- nautobot/core/tests/nautobot_config_without_example_apps.py +4 -0
- nautobot/core/tests/runner.py +8 -1
- nautobot/core/tests/test_api.py +5 -3
- nautobot/core/tests/test_breadcrumbs.py +27 -28
- nautobot/core/tests/test_checks.py +28 -0
- nautobot/core/tests/test_cli.py +40 -0
- nautobot/core/tests/test_config.py +2 -1
- nautobot/core/tests/test_forms.py +55 -13
- nautobot/core/tests/test_jobs.py +144 -3
- nautobot/core/tests/test_nautobot_server.py +2 -0
- nautobot/core/tests/test_navigations.py +76 -1
- nautobot/core/tests/test_patch_social_django.py +42 -0
- nautobot/core/tests/test_renderers.py +59 -0
- nautobot/core/tests/test_settings_schema.py +1 -0
- nautobot/core/tests/test_tables.py +3 -1
- nautobot/core/tests/test_templatetags_helpers.py +62 -13
- nautobot/core/tests/test_templatetags_ui_framework.py +4 -4
- nautobot/core/tests/test_titles.py +0 -16
- nautobot/core/tests/test_tree_queries.py +14 -1
- nautobot/core/tests/test_ui.py +123 -4
- nautobot/core/tests/test_utils.py +72 -5
- nautobot/core/tests/test_views.py +159 -31
- nautobot/core/ui/breadcrumbs.py +70 -29
- nautobot/core/ui/bulk_buttons.py +1 -1
- nautobot/core/ui/choices.py +143 -27
- nautobot/core/ui/constants.py +76 -12
- nautobot/core/ui/echarts.py +15 -20
- nautobot/core/ui/object_detail.py +143 -55
- nautobot/core/ui/titles.py +3 -6
- nautobot/core/urls.py +20 -9
- nautobot/core/utils/cache.py +2 -1
- nautobot/core/utils/filtering.py +28 -18
- nautobot/core/utils/lookup.py +49 -8
- nautobot/core/utils/module_loading.py +21 -0
- nautobot/core/utils/patch_social_django.py +128 -0
- nautobot/core/views/__init__.py +38 -1
- nautobot/core/views/generic.py +3 -3
- nautobot/core/views/mixins.py +45 -22
- nautobot/core/views/renderers.py +4 -3
- nautobot/core/views/viewsets.py +2 -1
- nautobot/data_validation/apps.py +1 -5
- nautobot/data_validation/custom_validators.py +4 -4
- nautobot/data_validation/filters.py +1 -1
- nautobot/data_validation/forms.py +40 -0
- nautobot/data_validation/migrations/0001_initial.py +0 -7
- nautobot/data_validation/migrations/0002_data_migration_from_app.py +3 -14
- nautobot/data_validation/models.py +16 -7
- nautobot/data_validation/navigation.py +8 -1
- nautobot/data_validation/tables.py +12 -5
- nautobot/data_validation/templates/data_validation/datacompliance_tab.html +1 -0
- nautobot/data_validation/templates/data_validation/device_constraints.html +61 -0
- nautobot/data_validation/tests/__init__.py +2 -2
- nautobot/data_validation/tests/migrations/test_migrations.py +83 -3
- nautobot/data_validation/tests/test_data_compliance_rules.py +12 -7
- nautobot/data_validation/tests/test_filters.py +8 -6
- nautobot/data_validation/tests/test_models.py +15 -0
- nautobot/data_validation/tests/test_views.py +190 -32
- nautobot/data_validation/urls.py +2 -5
- nautobot/data_validation/views.py +73 -40
- nautobot/dcim/api/serializers.py +3 -13
- nautobot/dcim/apps.py +4 -0
- nautobot/dcim/choices.py +65 -0
- nautobot/dcim/constants.py +7 -0
- nautobot/dcim/custom_validators.py +84 -0
- nautobot/dcim/factory.py +1 -1
- nautobot/dcim/filter_mixins.py +353 -4
- nautobot/dcim/{filters/__init__.py → filters.py} +15 -36
- nautobot/dcim/forms.py +90 -4
- nautobot/dcim/migrations/0075_interface_duplex_interface_speed_and_more.py +32 -0
- nautobot/dcim/migrations/{0075_add_deviceclusterassignment.py → 0076_add_deviceclusterassignment.py} +1 -1
- nautobot/dcim/migrations/{0076_device_cluster_to_clusters_data_migration.py → 0077_device_cluster_to_clusters_data_migration.py} +1 -1
- nautobot/dcim/migrations/{0077_remove_device_cluster.py → 0078_remove_device_cluster.py} +1 -1
- nautobot/dcim/migrations/0079_remove_device_location_tenant_name_uniqueness.py +16 -0
- nautobot/dcim/migrations/0080_device_name_data_migration.py +59 -0
- nautobot/dcim/migrations/0081_alter_device_device_redundancy_group_priority_and_more.py +25 -0
- nautobot/dcim/models/device_component_templates.py +33 -1
- nautobot/dcim/models/device_components.py +98 -64
- nautobot/dcim/models/devices.py +30 -20
- nautobot/dcim/navigation.py +7 -6
- nautobot/dcim/tables/devices.py +18 -0
- nautobot/dcim/tables/devicetypes.py +8 -1
- nautobot/dcim/tables/racks.py +0 -2
- nautobot/dcim/tables/template_code.py +15 -15
- nautobot/dcim/templates/dcim/cable_connect.html +28 -112
- nautobot/dcim/templates/dcim/cable_trace.html +0 -4
- nautobot/dcim/templates/dcim/{cable_edit.html → cable_update.html} +1 -1
- nautobot/dcim/templates/dcim/consoleport.html +7 -6
- nautobot/dcim/templates/dcim/consoleserverport.html +7 -6
- nautobot/dcim/templates/dcim/device/config.html +2 -2
- nautobot/dcim/templates/dcim/device/lldp_neighbors.html +1 -1
- nautobot/dcim/templates/dcim/device/status.html +8 -8
- nautobot/dcim/templates/dcim/device.html +1 -1
- nautobot/dcim/templates/dcim/device_component_add.html +2 -2
- nautobot/dcim/templates/dcim/device_create.html +5 -3
- nautobot/dcim/templates/dcim/device_interface_delete.html +1 -1
- nautobot/dcim/templates/dcim/device_list.html +73 -10
- nautobot/dcim/templates/dcim/devicebay.html +1 -1
- nautobot/dcim/templates/dcim/devicebay_populate.html +2 -2
- nautobot/dcim/templates/dcim/devicetype_component_add.html +2 -2
- nautobot/dcim/templates/dcim/footer_convert_to_contact_or_team_record.html +14 -0
- nautobot/dcim/templates/dcim/frontport.html +10 -9
- nautobot/dcim/templates/dcim/inc/devicetype_component_table.html +1 -1
- nautobot/dcim/templates/dcim/inc/edit_form_softwareversion_js.html +2 -2
- nautobot/dcim/templates/dcim/inc/moduletype_component_table.html +1 -1
- nautobot/dcim/templates/dcim/inc/rack_elevation.html +1 -1
- nautobot/dcim/templates/dcim/interface.html +35 -7
- nautobot/dcim/templates/dcim/interface_bulk_delete.html +1 -1
- nautobot/dcim/templates/dcim/interface_edit.html +2 -0
- nautobot/dcim/templates/dcim/inventoryitem.html +1 -1
- nautobot/dcim/templates/dcim/inventoryitem_add.html +3 -1
- nautobot/dcim/templates/dcim/inventoryitem_bulk_delete.html +1 -1
- nautobot/dcim/templates/dcim/inventoryitem_edit.html +3 -1
- nautobot/dcim/templates/dcim/module/base.html +49 -9
- nautobot/dcim/templates/dcim/module_consoleports.html +1 -1
- nautobot/dcim/templates/dcim/module_consoleserverports.html +1 -1
- nautobot/dcim/templates/dcim/module_frontports.html +1 -1
- nautobot/dcim/templates/dcim/module_interfaces.html +1 -1
- nautobot/dcim/templates/dcim/module_list.html +57 -8
- nautobot/dcim/templates/dcim/module_modulebays.html +1 -1
- nautobot/dcim/templates/dcim/module_poweroutlets.html +1 -1
- nautobot/dcim/templates/dcim/module_powerports.html +1 -1
- nautobot/dcim/templates/dcim/module_rearports.html +1 -1
- nautobot/dcim/templates/dcim/modulefamily_retrieve.html +1 -1
- nautobot/dcim/templates/dcim/moduletype_list.html +2 -2
- nautobot/dcim/templates/dcim/moduletype_retrieve.html +49 -9
- nautobot/dcim/templates/dcim/platform_create.html +1 -1
- nautobot/dcim/templates/dcim/poweroutlet.html +1 -1
- nautobot/dcim/templates/dcim/powerport.html +6 -5
- nautobot/dcim/templates/dcim/rack_elevation_list.html +17 -5
- nautobot/dcim/templates/dcim/rack_retrieve.html +22 -15
- nautobot/dcim/templates/dcim/rearport.html +8 -7
- nautobot/dcim/templates/dcim/trace/cable.html +1 -1
- nautobot/dcim/templates/dcim/virtualchassis_add_member.html +16 -14
- nautobot/dcim/templates/dcim/virtualchassis_update.html +15 -7
- nautobot/dcim/tests/integration/test_controller.py +4 -6
- nautobot/dcim/tests/integration/test_controller_managed_device_group.py +1 -5
- nautobot/dcim/tests/integration/test_create_device.py +0 -2
- nautobot/dcim/tests/integration/test_device_bulk_operations.py +1 -3
- nautobot/dcim/tests/integration/test_fileinputpicker.py +6 -10
- nautobot/dcim/tests/integration/test_location_bulk_operations.py +0 -2
- nautobot/dcim/tests/integration/test_module_bay_position.py +3 -4
- nautobot/dcim/tests/test_api.py +194 -6
- nautobot/dcim/tests/test_custom_validators.py +229 -0
- nautobot/dcim/tests/test_filters.py +55 -7
- nautobot/dcim/tests/test_forms.py +110 -8
- nautobot/dcim/tests/test_graphql.py +44 -1
- nautobot/dcim/tests/test_models.py +328 -4
- nautobot/dcim/tests/test_tables.py +160 -0
- nautobot/dcim/tests/test_views.py +132 -29
- nautobot/dcim/urls.py +64 -21
- nautobot/dcim/utils.py +3 -3
- nautobot/dcim/views.py +777 -397
- nautobot/extras/api/views.py +60 -45
- nautobot/extras/choices.py +2 -13
- nautobot/extras/datasources/git.py +3 -1
- nautobot/extras/{filters/mixins.py → filter_mixins.py} +1 -1
- nautobot/extras/{filters/customfields.py → filter_mixins_customfields.py} +42 -6
- nautobot/extras/{filters/__init__.py → filters.py} +33 -48
- nautobot/extras/forms/forms.py +14 -15
- nautobot/extras/forms/mixins.py +0 -41
- nautobot/extras/jobs.py +2 -0
- nautobot/extras/jobs_ui.py +4 -3
- nautobot/extras/management/__init__.py +11 -0
- nautobot/extras/management/commands/refresh_dynamic_group_member_caches.py +4 -1
- nautobot/extras/migrations/0127_approval_workflow_models.py +6 -6
- nautobot/extras/migrations/0129_jobresult_debug_log_count_jobresult_error_log_count_and_more.py +37 -0
- nautobot/extras/migrations/0130_jobresult_generate_log_entry_counts.py +42 -0
- nautobot/extras/migrations/0131_configcontext_device_families.py +18 -0
- nautobot/extras/models/__init__.py +1 -2
- nautobot/extras/models/approvals.py +33 -14
- nautobot/extras/models/change_logging.py +4 -0
- nautobot/extras/models/contacts.py +2 -0
- nautobot/extras/models/groups.py +44 -5
- nautobot/extras/models/jobs.py +60 -4
- nautobot/extras/models/mixins.py +28 -0
- nautobot/extras/models/models.py +23 -2
- nautobot/extras/models/secrets.py +1 -0
- nautobot/extras/models/statuses.py +0 -15
- nautobot/extras/navigation.py +13 -9
- nautobot/extras/plugins/__init__.py +33 -55
- nautobot/extras/plugins/marketplace_manifest.yml +49 -1
- nautobot/extras/plugins/tables.py +3 -3
- nautobot/extras/plugins/urls.py +2 -21
- nautobot/extras/plugins/utils.py +1 -33
- nautobot/extras/plugins/views.py +0 -9
- nautobot/extras/querysets.py +8 -0
- nautobot/extras/signals.py +20 -19
- nautobot/extras/tables.py +64 -68
- nautobot/extras/templates/django_ajax_tables/ajax_wrapper.html +2 -0
- nautobot/extras/templates/extras/approval_dashboard.html +7 -5
- nautobot/extras/templates/extras/approvalworkflowdefinition_update.html +4 -2
- nautobot/extras/templates/extras/approvalworkflowstage_retrieve.html +20 -12
- nautobot/extras/templates/extras/configcontext_update.html +1 -0
- nautobot/extras/templates/extras/configcontextschema_validation.html +2 -2
- nautobot/extras/templates/extras/dynamicgroup_retrieve.html +11 -5
- nautobot/extras/templates/extras/dynamicgroup_update.html +1 -1
- nautobot/extras/templates/extras/gitrepository_result.html +0 -2
- nautobot/extras/templates/extras/inc/approval_buttons_column.html +20 -6
- nautobot/extras/templates/extras/inc/bulk_edit_overridable_field.html +8 -7
- nautobot/extras/templates/extras/inc/configcontext_format.html +10 -3
- nautobot/extras/templates/extras/inc/graphqlquery_execute.html +71 -0
- nautobot/extras/templates/extras/inc/job_tiles.html +15 -3
- nautobot/extras/templates/extras/inc/json_format.html +10 -3
- nautobot/extras/templates/extras/inc/overridable_field.html +13 -12
- nautobot/extras/templates/extras/job.html +29 -12
- nautobot/extras/templates/extras/job_bulk_edit.html +18 -0
- nautobot/extras/templates/extras/job_edit.html +52 -46
- nautobot/extras/templates/extras/job_list.html +29 -25
- nautobot/extras/templates/extras/marketplace.html +5 -9
- nautobot/extras/templates/extras/object_configcontext.html +1 -1
- nautobot/extras/templates/extras/object_dynamicgroups.html +2 -2
- nautobot/extras/templates/extras/objectchange_retrieve.html +19 -39
- nautobot/extras/templates/extras/plugin_detail.html +29 -24
- nautobot/extras/templates/extras/plugins_list.html +16 -26
- nautobot/extras/templates/extras/role_retrieve.html +64 -0
- nautobot/extras/templates/extras/scheduledjob.html +4 -2
- nautobot/extras/templates/extras/secret_create.html +1 -1
- nautobot/extras/templatetags/custom_links.py +12 -12
- nautobot/extras/templatetags/job_buttons.py +14 -12
- nautobot/extras/test_jobs/invalid_import.py +9 -0
- nautobot/extras/test_jobs/log_counts_by_level.py +23 -0
- nautobot/extras/test_jobs/missing_import.py +11 -0
- nautobot/extras/tests/integration/test_computedfields.py +8 -9
- nautobot/extras/tests/integration/test_configcontextschema.py +27 -26
- nautobot/extras/tests/integration/test_customfields.py +9 -10
- nautobot/extras/tests/integration/test_dynamicgroups.py +12 -9
- nautobot/extras/tests/integration/test_plugin_banner.py +3 -0
- nautobot/extras/tests/integration/test_plugins.py +18 -6
- nautobot/extras/tests/integration/test_relationships.py +0 -2
- nautobot/extras/tests/test_api.py +90 -18
- nautobot/extras/tests/test_approvals.py +38 -38
- nautobot/extras/tests/test_changelog.py +59 -5
- nautobot/extras/tests/test_customfields.py +22 -13
- nautobot/extras/tests/test_customfields_filters.py +479 -0
- nautobot/extras/tests/test_dynamicgroups.py +39 -1
- nautobot/extras/tests/test_filters.py +57 -22
- nautobot/extras/tests/test_forms.py +18 -21
- nautobot/extras/tests/test_jobs.py +25 -4
- nautobot/extras/tests/test_migrations.py +1 -0
- nautobot/extras/tests/test_models.py +51 -33
- nautobot/extras/tests/test_plugins.py +36 -10
- nautobot/extras/tests/test_utils.py +3 -4
- nautobot/extras/tests/test_views.py +52 -112
- nautobot/extras/urls.py +0 -14
- nautobot/extras/views.py +164 -71
- nautobot/ipam/factory.py +7 -0
- nautobot/ipam/filter_mixins.py +38 -0
- nautobot/ipam/filters.py +53 -38
- nautobot/ipam/formfields.py +1 -1
- nautobot/ipam/forms.py +6 -3
- nautobot/ipam/migrations/0030_ipam__namespaces.py +13 -0
- nautobot/ipam/migrations/0031_ipam___data_migrations.py +4 -1
- nautobot/ipam/migrations/0054_namespace_tenant.py +25 -0
- nautobot/ipam/models.py +29 -2
- nautobot/ipam/navigation.py +3 -2
- nautobot/ipam/signals.py +71 -0
- nautobot/ipam/tables.py +19 -6
- nautobot/ipam/templates/ipam/inc/toggle_available.html +10 -10
- nautobot/ipam/templates/ipam/inc/vlangroup_header.html +1 -0
- nautobot/ipam/templates/ipam/ipaddress.html +14 -0
- nautobot/ipam/templates/ipam/ipaddress_merge.html +3 -3
- nautobot/ipam/templates/ipam/ipaddresstointerface_retrieve.html +1 -0
- nautobot/ipam/templates/ipam/namespace_ip_addresses.html +1 -1
- nautobot/ipam/templates/ipam/namespace_prefixes.html +1 -1
- nautobot/ipam/templates/ipam/namespace_update.html +15 -0
- nautobot/ipam/templates/ipam/namespace_vrfs.html +1 -1
- nautobot/ipam/templates/ipam/prefix_delete.html +1 -1
- nautobot/ipam/templates/ipam/prefix_list.html +14 -13
- nautobot/ipam/templates/ipam/vlan_interfaces.html +1 -1
- nautobot/ipam/templates/ipam/vlan_vminterfaces.html +1 -1
- nautobot/ipam/tests/migration/test_migrations.py +89 -0
- nautobot/ipam/tests/test_api.py +13 -6
- nautobot/ipam/tests/test_filters.py +36 -1
- nautobot/ipam/tests/test_forms.py +1 -1
- nautobot/ipam/tests/test_models.py +44 -2
- nautobot/ipam/tests/test_tables.py +1 -2
- nautobot/ipam/tests/test_utils.py +1 -1
- nautobot/ipam/tests/test_views.py +13 -14
- nautobot/ipam/ui.py +0 -17
- nautobot/ipam/utils/migrations.py +16 -2
- nautobot/ipam/utils/testing.py +9 -3
- nautobot/ipam/views.py +53 -11
- nautobot/load_balancers/__init__.py +0 -0
- nautobot/load_balancers/api/__init__.py +1 -0
- nautobot/load_balancers/api/serializers.py +75 -0
- nautobot/load_balancers/api/urls.py +23 -0
- nautobot/load_balancers/api/views.py +61 -0
- nautobot/load_balancers/apps.py +17 -0
- nautobot/load_balancers/choices.py +167 -0
- nautobot/load_balancers/filters.py +225 -0
- nautobot/load_balancers/forms.py +532 -0
- nautobot/load_balancers/management/commands/__init__.py +0 -0
- nautobot/load_balancers/management/commands/generate_load_balancer_models_test_data.py +38 -0
- nautobot/load_balancers/migrations/0001_initial.py +465 -0
- nautobot/load_balancers/migrations/0002_create_default_statuses_pool_members.py +31 -0
- nautobot/load_balancers/migrations/__init__.py +0 -0
- nautobot/load_balancers/models.py +423 -0
- nautobot/load_balancers/navigation.py +80 -0
- nautobot/load_balancers/tables.py +255 -0
- nautobot/load_balancers/tests/__init__.py +474 -0
- nautobot/load_balancers/tests/test_api.py +353 -0
- nautobot/load_balancers/tests/test_filters.py +134 -0
- nautobot/load_balancers/tests/test_forms.py +266 -0
- nautobot/load_balancers/tests/test_models.py +195 -0
- nautobot/load_balancers/tests/test_views.py +229 -0
- nautobot/load_balancers/urls.py +17 -0
- nautobot/load_balancers/views.py +248 -0
- nautobot/project-static/dist/css/github-dark.min.css +10 -0
- nautobot/project-static/dist/css/github.min.css +10 -0
- nautobot/project-static/dist/css/nautobot.css +1 -11
- nautobot/project-static/dist/css/nautobot.css.map +1 -1
- nautobot/project-static/dist/js/libraries.js +1 -1
- nautobot/project-static/dist/js/libraries.js.map +1 -1
- nautobot/project-static/dist/js/nautobot.js +1 -1
- nautobot/project-static/dist/js/nautobot.js.map +1 -1
- nautobot/project-static/js/cabletrace.js +1 -1
- nautobot/project-static/js/forms.js +13 -0
- nautobot/project-static/js/interface_filtering.js +20 -16
- nautobot/project-static/nautobot-icons/battery-3.svg +3 -0
- nautobot/project-static/nautobot-icons/bus-globe.svg +3 -0
- nautobot/project-static/nautobot-icons/bus-shield-check.svg +3 -0
- nautobot/project-static/nautobot-icons/bus-shield.svg +3 -0
- nautobot/project-static/nautobot-icons/cloud.svg +1 -1
- nautobot/project-static/nautobot-icons/control-panel.svg +1 -1
- nautobot/project-static/nautobot-icons/device-lifecycle.svg +1 -1
- nautobot/project-static/nautobot-icons/elements.svg +1 -1
- nautobot/project-static/nautobot-icons/extensibility.svg +3 -0
- nautobot/project-static/nautobot-icons/hammer.svg +1 -1
- nautobot/project-static/nautobot-icons/organization.svg +3 -0
- nautobot/project-static/nautobot-icons/secrets.svg +1 -1
- nautobot/project-static/nautobot-icons/security.svg +3 -0
- nautobot/project-static/nautobot-icons/server.svg +1 -1
- nautobot/project-static/nautobot-icons/star-filled.svg +1 -1
- nautobot/project-static/nautobot-icons/star.svg +1 -1
- nautobot/tenancy/api/serializers.py +1 -0
- nautobot/tenancy/api/views.py +2 -1
- nautobot/tenancy/{filters/__init__.py → filters.py} +2 -10
- nautobot/tenancy/navigation.py +3 -1
- nautobot/tenancy/tests/test_filters.py +0 -2
- nautobot/tenancy/views.py +2 -1
- nautobot/ui/package-lock.json +87 -4
- nautobot/ui/package.json +2 -1
- nautobot/ui/src/js/collapse.js +3 -3
- nautobot/ui/src/js/nautobot.js +16 -1
- nautobot/ui/src/js/select2.js +53 -2
- nautobot/ui/src/scss/colors.scss +1 -1
- nautobot/ui/src/scss/nautobot.scss +112 -30
- nautobot/ui/webpack.config.js +13 -0
- nautobot/users/templates/users/preferences.html +11 -2
- nautobot/users/templates/users/profile.html +45 -12
- nautobot/users/templates/users/sessionkey_delete.html +1 -1
- nautobot/users/tests/test_api.py +4 -0
- nautobot/users/views.py +4 -2
- nautobot/virtualization/filters.py +6 -1
- nautobot/virtualization/models.py +1 -68
- nautobot/virtualization/navigation.py +3 -2
- nautobot/virtualization/templates/virtualization/virtual_machine_vminterface_delete.html +1 -1
- nautobot/virtualization/templates/virtualization/virtualmachine_list.html +2 -2
- nautobot/virtualization/templates/virtualization/virtualmachine_update.html +3 -1
- nautobot/virtualization/tests/test_api.py +3 -0
- nautobot/virtualization/tests/test_filters.py +10 -1
- nautobot/virtualization/tests/test_models.py +45 -4
- nautobot/virtualization/views.py +4 -1
- nautobot/vpn/__init__.py +0 -0
- nautobot/vpn/api/serializers.py +113 -0
- nautobot/vpn/api/urls.py +19 -0
- nautobot/vpn/api/views.py +70 -0
- nautobot/vpn/apps.py +8 -0
- nautobot/vpn/choices.py +171 -0
- nautobot/vpn/factory.py +219 -0
- nautobot/vpn/filters.py +234 -0
- nautobot/vpn/forms.py +487 -0
- nautobot/vpn/homepage.py +19 -0
- nautobot/vpn/migrations/0001_initial.py +541 -0
- nautobot/vpn/migrations/0002_populate_defaults.py +199 -0
- nautobot/vpn/migrations/__init__.py +0 -0
- nautobot/vpn/models.py +535 -0
- nautobot/vpn/navigation.py +98 -0
- nautobot/vpn/tables.py +383 -0
- nautobot/vpn/templates/vpn/vpnprofile_create.html +150 -0
- nautobot/vpn/tests/__init__.py +0 -0
- nautobot/vpn/tests/test_api.py +336 -0
- nautobot/vpn/tests/test_filters.py +139 -0
- nautobot/vpn/tests/test_forms.py +293 -0
- nautobot/vpn/tests/test_models.py +147 -0
- nautobot/vpn/tests/test_views.py +300 -0
- nautobot/vpn/urls.py +16 -0
- nautobot/vpn/views.py +495 -0
- nautobot/wireless/navigation.py +3 -2
- nautobot/wireless/tests/integration/test_radio_profile.py +1 -5
- nautobot/wireless/tests/test_api.py +1 -1
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0rc1.dist-info}/METADATA +15 -15
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0rc1.dist-info}/RECORD +514 -572
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0rc1.dist-info}/entry_points.txt +1 -0
- nautobot/circuits/templates/circuits/circuit.html +0 -2
- nautobot/circuits/templates/circuits/circuit_edit.html +0 -2
- nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -2
- nautobot/circuits/templates/circuits/circuit_update.html +0 -1
- nautobot/circuits/templates/circuits/circuittermination.html +0 -2
- nautobot/circuits/templates/circuits/circuittermination_edit.html +0 -2
- nautobot/circuits/templates/circuits/circuittermination_retrieve.html +0 -2
- nautobot/circuits/templates/circuits/circuittermination_update.html +0 -1
- nautobot/circuits/templates/circuits/circuittype.html +0 -2
- nautobot/circuits/templates/circuits/circuittype_retrieve.html +0 -2
- nautobot/circuits/templates/circuits/inc/circuit_termination.html +0 -85
- nautobot/circuits/templates/circuits/provider.html +0 -2
- nautobot/circuits/templates/circuits/provider_edit.html +0 -2
- nautobot/circuits/templates/circuits/provider_retrieve.html +0 -1
- nautobot/circuits/templates/circuits/provider_update.html +0 -1
- nautobot/circuits/templates/circuits/providernetwork.html +0 -2
- nautobot/circuits/templates/circuits/providernetwork_retrieve.html +0 -2
- nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +0 -2
- nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +0 -2
- nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +0 -2
- nautobot/cloud/templates/cloud/cloudservice_retrieve.html +0 -2
- nautobot/core/templates/buttons/import.html +0 -9
- nautobot/data_validation/template_content.py +0 -42
- nautobot/data_validation/templates/data_validation/datacompliance_retrieve.html +0 -1
- nautobot/dcim/filters/mixins.py +0 -354
- nautobot/dcim/templates/dcim/controller/base.html +0 -2
- nautobot/dcim/templates/dcim/controller_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +0 -2
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/device/base.html +0 -2
- nautobot/dcim/templates/dcim/device/consoleports.html +0 -2
- nautobot/dcim/templates/dcim/device/consoleserverports.html +0 -2
- nautobot/dcim/templates/dcim/device/devicebays.html +0 -2
- nautobot/dcim/templates/dcim/device/frontports.html +0 -2
- nautobot/dcim/templates/dcim/device/interfaces.html +0 -2
- nautobot/dcim/templates/dcim/device/inventory.html +0 -2
- nautobot/dcim/templates/dcim/device/modulebays.html +0 -2
- nautobot/dcim/templates/dcim/device/poweroutlets.html +0 -2
- nautobot/dcim/templates/dcim/device/powerports.html +0 -2
- nautobot/dcim/templates/dcim/device/rearports.html +0 -2
- nautobot/dcim/templates/dcim/device/wireless.html +0 -2
- nautobot/dcim/templates/dcim/device_component.html +0 -2
- nautobot/dcim/templates/dcim/device_edit.html +0 -2
- nautobot/dcim/templates/dcim/devicefamily_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/deviceredundancygroup_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/devicetype.html +0 -2
- nautobot/dcim/templates/dcim/devicetype_edit.html +0 -2
- nautobot/dcim/templates/dcim/devicetype_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/inc/device_napalm_tabs.html +0 -1
- nautobot/dcim/templates/dcim/interfaceredundancygroup_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/location.html +0 -2
- nautobot/dcim/templates/dcim/location_edit.html +0 -2
- nautobot/dcim/templates/dcim/location_retrieve.html +0 -243
- nautobot/dcim/templates/dcim/locationtype.html +0 -2
- nautobot/dcim/templates/dcim/locationtype_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/manufacturer.html +0 -2
- nautobot/dcim/templates/dcim/modulebay_retrieve.html +0 -1
- nautobot/dcim/templates/dcim/platform.html +0 -2
- nautobot/dcim/templates/dcim/powerfeed.html +0 -2
- nautobot/dcim/templates/dcim/powerfeed_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/powerpanel.html +0 -2
- nautobot/dcim/templates/dcim/powerpanel_edit.html +0 -2
- nautobot/dcim/templates/dcim/powerpanel_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/rack.html +0 -2
- nautobot/dcim/templates/dcim/rack_edit.html +0 -2
- nautobot/dcim/templates/dcim/rackgroup.html +0 -2
- nautobot/dcim/templates/dcim/rackreservation.html +0 -2
- nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/softwareversion_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/virtualchassis.html +0 -2
- nautobot/dcim/templates/dcim/virtualchassis_add.html +0 -2
- nautobot/dcim/templates/dcim/virtualchassis_edit.html +0 -2
- nautobot/dcim/templates/dcim/virtualchassis_retrieve.html +0 -2
- nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +0 -2
- nautobot/dcim/ui.py +0 -29
- nautobot/extras/templates/extras/computedfield.html +0 -2
- nautobot/extras/templates/extras/computedfield_retrieve.html +0 -2
- nautobot/extras/templates/extras/configcontext.html +0 -2
- nautobot/extras/templates/extras/configcontext_edit.html +0 -2
- nautobot/extras/templates/extras/configcontext_retrieve.html +0 -2
- nautobot/extras/templates/extras/configcontextschema.html +0 -2
- nautobot/extras/templates/extras/configcontextschema_edit.html +0 -2
- nautobot/extras/templates/extras/contact_retrieve.html +0 -2
- nautobot/extras/templates/extras/customfield.html +0 -2
- nautobot/extras/templates/extras/customfield_edit.html +0 -2
- nautobot/extras/templates/extras/customfield_retrieve.html +0 -2
- nautobot/extras/templates/extras/customlink.html +0 -2
- nautobot/extras/templates/extras/dynamicgroup.html +0 -2
- nautobot/extras/templates/extras/dynamicgroup_edit.html +0 -2
- nautobot/extras/templates/extras/exporttemplate.html +0 -2
- nautobot/extras/templates/extras/gitrepository.html +0 -2
- nautobot/extras/templates/extras/gitrepository_object_edit.html +0 -2
- nautobot/extras/templates/extras/graphqlquery.html +0 -2
- nautobot/extras/templates/extras/graphqlquery_list.html +0 -1
- nautobot/extras/templates/extras/graphqlquery_retrieve.html +0 -97
- nautobot/extras/templates/extras/job_detail.html +0 -2
- nautobot/extras/templates/extras/jobbutton_retrieve.html +0 -2
- nautobot/extras/templates/extras/jobhook.html +0 -2
- nautobot/extras/templates/extras/jobqueue_retrieve.html +0 -2
- nautobot/extras/templates/extras/jobresult.html +0 -2
- nautobot/extras/templates/extras/metadatatype_retrieve.html +0 -2
- nautobot/extras/templates/extras/note.html +0 -2
- nautobot/extras/templates/extras/note_retrieve.html +0 -1
- nautobot/extras/templates/extras/object_changelog.html +0 -2
- nautobot/extras/templates/extras/object_notes.html +0 -2
- nautobot/extras/templates/extras/objectchange.html +0 -2
- nautobot/extras/templates/extras/objectchange_list.html +0 -3
- nautobot/extras/templates/extras/relationship.html +0 -1
- nautobot/extras/templates/extras/secret.html +0 -1
- nautobot/extras/templates/extras/secret_edit.html +0 -1
- nautobot/extras/templates/extras/secretsgroup.html +0 -2
- nautobot/extras/templates/extras/secretsgroup_edit.html +0 -2
- nautobot/extras/templates/extras/secretsgroup_retrieve.html +0 -2
- nautobot/extras/templates/extras/status.html +0 -2
- nautobot/extras/templates/extras/tag.html +0 -2
- nautobot/extras/templates/extras/tag_edit.html +0 -2
- nautobot/extras/templates/extras/tag_retrieve.html +0 -2
- nautobot/extras/templates/extras/team_retrieve.html +0 -2
- nautobot/ipam/templates/ipam/inc/prefix_header_extra_content_table.html +0 -4
- nautobot/ipam/templates/ipam/namespace_retrieve.html +0 -1
- nautobot/ipam/templates/ipam/prefix.html +0 -2
- nautobot/ipam/templates/ipam/prefix_edit.html +0 -1
- nautobot/ipam/templates/ipam/prefix_retrieve.html +0 -2
- nautobot/ipam/templates/ipam/rir.html +0 -2
- nautobot/ipam/templates/ipam/routetarget.html +0 -1
- nautobot/ipam/templates/ipam/service.html +0 -2
- nautobot/ipam/templates/ipam/service_edit.html +0 -2
- nautobot/ipam/templates/ipam/service_retrieve.html +0 -2
- nautobot/ipam/templates/ipam/vlan.html +0 -2
- nautobot/ipam/templates/ipam/vlan_edit.html +0 -2
- nautobot/ipam/templates/ipam/vlan_retrieve.html +0 -2
- nautobot/ipam/templates/ipam/vlangroup.html +0 -2
- nautobot/ipam/templates/ipam/vrf.html +0 -1
- nautobot/tenancy/templates/tenancy/tenant.html +0 -2
- nautobot/tenancy/templates/tenancy/tenant_edit.html +0 -2
- nautobot/tenancy/templates/tenancy/tenantgroup.html +0 -2
- nautobot/tenancy/templates/tenancy/tenantgroup_retrieve.html +0 -1
- nautobot/virtualization/templates/virtualization/clustergroup.html +0 -2
- nautobot/virtualization/templates/virtualization/clustertype.html +0 -2
- nautobot/virtualization/templates/virtualization/virtualmachine.html +0 -2
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +0 -2
- nautobot/virtualization/templates/virtualization/virtualmachine_retrieve.html +0 -2
- nautobot/wireless/templates/wireless/radioprofile_retrieve.html +0 -2
- nautobot/wireless/templates/wireless/supporteddatarate_retrieve.html +0 -2
- nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +0 -2
- /nautobot/dcim/templates/dcim/{cable.html → cable_retrieve.html} +0 -0
- /nautobot/tenancy/{filters/mixins.py → filter_mixins.py} +0 -0
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0rc1.dist-info}/LICENSE.txt +0 -0
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0rc1.dist-info}/NOTICE +0 -0
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0rc1.dist-info}/WHEEL +0 -0
|
@@ -6,7 +6,7 @@ from django.contrib.auth import get_user_model
|
|
|
6
6
|
from django.contrib.auth.models import Group
|
|
7
7
|
from django.contrib.contenttypes.models import ContentType
|
|
8
8
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
|
9
|
-
from django.test import override_settings, RequestFactory
|
|
9
|
+
from django.test import override_settings, RequestFactory, tag
|
|
10
10
|
from django.utils.timezone import now
|
|
11
11
|
|
|
12
12
|
from nautobot.core.jobs import BulkDeleteObjects
|
|
@@ -14,6 +14,7 @@ from nautobot.core.testing import FilterTestCases
|
|
|
14
14
|
from nautobot.dcim.filters import DeviceFilterSet
|
|
15
15
|
from nautobot.dcim.models import (
|
|
16
16
|
Device,
|
|
17
|
+
DeviceFamily,
|
|
17
18
|
DeviceType,
|
|
18
19
|
Interface,
|
|
19
20
|
Location,
|
|
@@ -165,35 +166,35 @@ class ApprovalWorkflowTestMixin:
|
|
|
165
166
|
cls.approval_workflow_1_definition = ApprovalWorkflowDefinition.objects.create(
|
|
166
167
|
name="Test Approval Workflow 1 Definition",
|
|
167
168
|
model_content_type=cls.scheduledjob_ct,
|
|
168
|
-
|
|
169
|
+
weight=1,
|
|
169
170
|
)
|
|
170
171
|
cls.approval_workflow_2_definition = ApprovalWorkflowDefinition.objects.create(
|
|
171
172
|
name="Test Approval Workflow 2 Definition",
|
|
172
173
|
model_content_type=cls.scheduledjob_ct,
|
|
173
174
|
model_constraints={"name": "Bulk Delete Objects"},
|
|
174
|
-
|
|
175
|
+
weight=2,
|
|
175
176
|
)
|
|
176
177
|
cls.approval_workflow_3_definition = ApprovalWorkflowDefinition.objects.create(
|
|
177
178
|
name="Test Approval Workflow 3 Definition",
|
|
178
179
|
model_content_type=cls.scheduledjob_ct,
|
|
179
180
|
model_constraints={"name": "Bulk Delete Objects"},
|
|
180
|
-
|
|
181
|
+
weight=3,
|
|
181
182
|
)
|
|
182
183
|
cls.approval_workflow_4_definition = ApprovalWorkflowDefinition.objects.create(
|
|
183
184
|
name="Test Approval Workflow 4 Definition",
|
|
184
185
|
model_content_type=cls.scheduledjob_ct,
|
|
185
186
|
model_constraints={"name": "Bulk Delete Objects"},
|
|
186
|
-
|
|
187
|
+
weight=4,
|
|
187
188
|
)
|
|
188
189
|
cls.approval_workflow_5_definition = ApprovalWorkflowDefinition.objects.create(
|
|
189
190
|
name="Test Approval Workflow 5 Definition",
|
|
190
191
|
model_content_type=cls.scheduledjob_ct,
|
|
191
192
|
model_constraints={"name": "Bulk Delete Objects"},
|
|
192
|
-
|
|
193
|
+
weight=5,
|
|
193
194
|
)
|
|
194
195
|
cls.approval_workflow_1_stage_1_definition = ApprovalWorkflowStageDefinition.objects.create(
|
|
195
196
|
approval_workflow_definition=cls.approval_workflow_1_definition,
|
|
196
|
-
|
|
197
|
+
sequence=100,
|
|
197
198
|
name="Test Approval Workflow 1 Stage 1 Definition",
|
|
198
199
|
min_approvers=2,
|
|
199
200
|
denial_message="Stage 1 Denial Message",
|
|
@@ -201,7 +202,7 @@ class ApprovalWorkflowTestMixin:
|
|
|
201
202
|
)
|
|
202
203
|
cls.approval_workflow_1_stage_2_definition = ApprovalWorkflowStageDefinition.objects.create(
|
|
203
204
|
approval_workflow_definition=cls.approval_workflow_1_definition,
|
|
204
|
-
|
|
205
|
+
sequence=200,
|
|
205
206
|
name="Test Approval Workflow 1 Stage 2 Definition",
|
|
206
207
|
min_approvers=2,
|
|
207
208
|
denial_message="Stage 2 Denial Message",
|
|
@@ -209,7 +210,7 @@ class ApprovalWorkflowTestMixin:
|
|
|
209
210
|
)
|
|
210
211
|
cls.approval_workflow_1_stage_3_definition = ApprovalWorkflowStageDefinition.objects.create(
|
|
211
212
|
approval_workflow_definition=cls.approval_workflow_1_definition,
|
|
212
|
-
|
|
213
|
+
sequence=300,
|
|
213
214
|
name="Test Approval Workflow 1 Stage 3 Definition",
|
|
214
215
|
min_approvers=3,
|
|
215
216
|
denial_message="Stage 3 Denial Message",
|
|
@@ -217,7 +218,7 @@ class ApprovalWorkflowTestMixin:
|
|
|
217
218
|
)
|
|
218
219
|
cls.approval_workflow_1_stage_4_definition = ApprovalWorkflowStageDefinition.objects.create(
|
|
219
220
|
approval_workflow_definition=cls.approval_workflow_1_definition,
|
|
220
|
-
|
|
221
|
+
sequence=400,
|
|
221
222
|
name="Test Approval Workflow 1 Stage 4 Definition",
|
|
222
223
|
min_approvers=5,
|
|
223
224
|
denial_message="Stage 4 Denial Message",
|
|
@@ -225,7 +226,7 @@ class ApprovalWorkflowTestMixin:
|
|
|
225
226
|
)
|
|
226
227
|
cls.approval_workflow_1_stage_5_definition = ApprovalWorkflowStageDefinition.objects.create(
|
|
227
228
|
approval_workflow_definition=cls.approval_workflow_1_definition,
|
|
228
|
-
|
|
229
|
+
sequence=500,
|
|
229
230
|
name="Test Approval Workflow 1 Stage 5 Definition",
|
|
230
231
|
min_approvers=2,
|
|
231
232
|
denial_message="Stage 5 Denial Message",
|
|
@@ -233,7 +234,7 @@ class ApprovalWorkflowTestMixin:
|
|
|
233
234
|
)
|
|
234
235
|
cls.approval_workflow_1_stage_6_definition = ApprovalWorkflowStageDefinition.objects.create(
|
|
235
236
|
approval_workflow_definition=cls.approval_workflow_1_definition,
|
|
236
|
-
|
|
237
|
+
sequence=600,
|
|
237
238
|
name="Test Approval Workflow 1 Stage 6 Definition",
|
|
238
239
|
min_approvers=2,
|
|
239
240
|
denial_message="Stage 6 Denial Message",
|
|
@@ -241,7 +242,7 @@ class ApprovalWorkflowTestMixin:
|
|
|
241
242
|
)
|
|
242
243
|
cls.approval_workflow_2_stage_1_definition = ApprovalWorkflowStageDefinition.objects.create(
|
|
243
244
|
approval_workflow_definition=cls.approval_workflow_2_definition,
|
|
244
|
-
|
|
245
|
+
sequence=100,
|
|
245
246
|
name="Test Approval Workflow 2 Stage 1 Definition",
|
|
246
247
|
min_approvers=2,
|
|
247
248
|
denial_message="Stage 1 Denial Message",
|
|
@@ -249,7 +250,7 @@ class ApprovalWorkflowTestMixin:
|
|
|
249
250
|
)
|
|
250
251
|
cls.approval_workflow_2_stage_2_definition = ApprovalWorkflowStageDefinition.objects.create(
|
|
251
252
|
approval_workflow_definition=cls.approval_workflow_2_definition,
|
|
252
|
-
|
|
253
|
+
sequence=200,
|
|
253
254
|
name="Test Approval Workflow 2 Stage 2 Definition",
|
|
254
255
|
min_approvers=2,
|
|
255
256
|
denial_message="Stage 2 Denial Message",
|
|
@@ -257,7 +258,7 @@ class ApprovalWorkflowTestMixin:
|
|
|
257
258
|
)
|
|
258
259
|
cls.approval_workflow_2_stage_3_definition = ApprovalWorkflowStageDefinition.objects.create(
|
|
259
260
|
approval_workflow_definition=cls.approval_workflow_2_definition,
|
|
260
|
-
|
|
261
|
+
sequence=300,
|
|
261
262
|
name="Test Approval Workflow 2 Stage 3 Definition",
|
|
262
263
|
min_approvers=2,
|
|
263
264
|
denial_message="Stage 3 Denial Message",
|
|
@@ -265,7 +266,7 @@ class ApprovalWorkflowTestMixin:
|
|
|
265
266
|
)
|
|
266
267
|
cls.approval_workflow_3_stage_1_definition = ApprovalWorkflowStageDefinition.objects.create(
|
|
267
268
|
approval_workflow_definition=cls.approval_workflow_3_definition,
|
|
268
|
-
|
|
269
|
+
sequence=100,
|
|
269
270
|
name="Test Approval Workflow 3 Stage 1 Definition",
|
|
270
271
|
min_approvers=2,
|
|
271
272
|
denial_message="Stage 1 Denial Message",
|
|
@@ -273,7 +274,7 @@ class ApprovalWorkflowTestMixin:
|
|
|
273
274
|
)
|
|
274
275
|
cls.approval_workflow_3_stage_2_definition = ApprovalWorkflowStageDefinition.objects.create(
|
|
275
276
|
approval_workflow_definition=cls.approval_workflow_3_definition,
|
|
276
|
-
|
|
277
|
+
sequence=200,
|
|
277
278
|
name="Test Approval Workflow 3 Stage 2 Definition",
|
|
278
279
|
min_approvers=2,
|
|
279
280
|
denial_message="Stage 2 Denial Message",
|
|
@@ -281,7 +282,7 @@ class ApprovalWorkflowTestMixin:
|
|
|
281
282
|
)
|
|
282
283
|
cls.approval_workflow_3_stage_3_definition = ApprovalWorkflowStageDefinition.objects.create(
|
|
283
284
|
approval_workflow_definition=cls.approval_workflow_3_definition,
|
|
284
|
-
|
|
285
|
+
sequence=300,
|
|
285
286
|
name="Test Approval Workflow 3 Stage 3 Definition",
|
|
286
287
|
min_approvers=2,
|
|
287
288
|
denial_message="Stage 3 Denial Message",
|
|
@@ -442,7 +443,7 @@ class ApprovalWorkflowStageDefinitionFilterTestCase(ApprovalWorkflowTestMixin, F
|
|
|
442
443
|
("created",),
|
|
443
444
|
("last_updated",),
|
|
444
445
|
("approval_workflow_definition",),
|
|
445
|
-
("
|
|
446
|
+
("sequence",),
|
|
446
447
|
("name",),
|
|
447
448
|
("min_approvers",),
|
|
448
449
|
("denial_message",),
|
|
@@ -605,6 +606,8 @@ class ConfigContextTestCase(FilterTestCases.FilterTestCase):
|
|
|
605
606
|
("cluster_group", "cluster_groups__id"),
|
|
606
607
|
("cluster_group", "cluster_groups__name"),
|
|
607
608
|
("cluster_group_id", "cluster_groups__id"),
|
|
609
|
+
("device_family", "device_families__id"),
|
|
610
|
+
("device_family", "device_families__name"),
|
|
608
611
|
("device_type", "device_types__id"),
|
|
609
612
|
("device_type", "device_types__model"),
|
|
610
613
|
("device_type_id", "device_types__id"),
|
|
@@ -631,10 +634,28 @@ class ConfigContextTestCase(FilterTestCases.FilterTestCase):
|
|
|
631
634
|
|
|
632
635
|
manufacturer = Manufacturer.objects.first()
|
|
633
636
|
|
|
637
|
+
cls.device_families = (
|
|
638
|
+
DeviceFamily.objects.create(name="Device Family A"),
|
|
639
|
+
DeviceFamily.objects.create(name="Device Family B"),
|
|
640
|
+
DeviceFamily.objects.create(name="Device Family C"),
|
|
641
|
+
)
|
|
642
|
+
|
|
634
643
|
device_types = (
|
|
635
|
-
DeviceType.objects.create(
|
|
636
|
-
|
|
637
|
-
|
|
644
|
+
DeviceType.objects.create(
|
|
645
|
+
model="Device Type 1",
|
|
646
|
+
manufacturer=manufacturer,
|
|
647
|
+
device_family=cls.device_families[0],
|
|
648
|
+
),
|
|
649
|
+
DeviceType.objects.create(
|
|
650
|
+
model="Device Type 2",
|
|
651
|
+
manufacturer=manufacturer,
|
|
652
|
+
device_family=cls.device_families[1],
|
|
653
|
+
),
|
|
654
|
+
DeviceType.objects.create(
|
|
655
|
+
model="Device Type 3",
|
|
656
|
+
manufacturer=manufacturer,
|
|
657
|
+
device_family=cls.device_families[2],
|
|
658
|
+
),
|
|
638
659
|
)
|
|
639
660
|
cls.device_types = device_types
|
|
640
661
|
|
|
@@ -669,6 +690,7 @@ class ConfigContextTestCase(FilterTestCases.FilterTestCase):
|
|
|
669
690
|
)
|
|
670
691
|
c.locations.set([cls.locations[i]])
|
|
671
692
|
c.roles.set([device_roles[i]])
|
|
693
|
+
c.device_families.set([cls.device_families[i]])
|
|
672
694
|
c.device_types.set([device_types[i]])
|
|
673
695
|
c.platforms.set([platforms[i]])
|
|
674
696
|
c.cluster_groups.set([cluster_groups[i]])
|
|
@@ -1331,6 +1353,7 @@ class JobFilterSetTestCase(FilterTestCases.FilterTestCase):
|
|
|
1331
1353
|
params = {"dryrun_default": True}
|
|
1332
1354
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0)
|
|
1333
1355
|
|
|
1356
|
+
@tag("example_app")
|
|
1334
1357
|
def test_hidden(self):
|
|
1335
1358
|
params = {"hidden": True}
|
|
1336
1359
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
|
@@ -1341,6 +1364,7 @@ class JobFilterSetTestCase(FilterTestCases.FilterTestCase):
|
|
|
1341
1364
|
self.filterset(params, self.queryset).qs, self.queryset.filter(read_only=True)
|
|
1342
1365
|
)
|
|
1343
1366
|
|
|
1367
|
+
@tag("example_app")
|
|
1344
1368
|
def test_is_job_hook_receiver(self):
|
|
1345
1369
|
params = {"is_job_hook_receiver": True}
|
|
1346
1370
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
|
@@ -2140,6 +2164,8 @@ class SecretTestCase(FilterTestCases.FilterTestCase):
|
|
|
2140
2164
|
("created",),
|
|
2141
2165
|
("last_updated",),
|
|
2142
2166
|
("name",),
|
|
2167
|
+
("secrets_groups", "secrets_groups__id"),
|
|
2168
|
+
("secrets_groups", "secrets_groups__name"),
|
|
2143
2169
|
("tags", "tags__id"),
|
|
2144
2170
|
("tags", "tags__name"),
|
|
2145
2171
|
)
|
|
@@ -2168,6 +2194,15 @@ class SecretTestCase(FilterTestCases.FilterTestCase):
|
|
|
2168
2194
|
secrets[0].tags.set(Tag.objects.get_for_model(Secret))
|
|
2169
2195
|
secrets[1].tags.set(Tag.objects.get_for_model(Secret)[:3])
|
|
2170
2196
|
|
|
2197
|
+
secrets_groups = (
|
|
2198
|
+
SecretsGroup.objects.create(
|
|
2199
|
+
name="Secrets Group 1",
|
|
2200
|
+
),
|
|
2201
|
+
SecretsGroup.objects.create(name="Secrets Group 2"),
|
|
2202
|
+
)
|
|
2203
|
+
secrets_groups[0].secrets.set([secrets[0]])
|
|
2204
|
+
secrets_groups[1].secrets.set([secrets[1]])
|
|
2205
|
+
|
|
2171
2206
|
def test_provider(self):
|
|
2172
2207
|
params = {"provider": ["environment-variable"]}
|
|
2173
2208
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
|
+
from unittest import skip
|
|
2
3
|
import warnings
|
|
3
4
|
|
|
4
5
|
from django.contrib.auth import get_user_model
|
|
@@ -14,14 +15,9 @@ from nautobot.extras.choices import CustomFieldTypeChoices, RelationshipTypeChoi
|
|
|
14
15
|
from nautobot.extras.forms import (
|
|
15
16
|
ConfigContextFilterForm,
|
|
16
17
|
ConfigContextForm,
|
|
17
|
-
CustomFieldModelBulkEditFormMixin,
|
|
18
18
|
CustomFieldModelFormMixin,
|
|
19
19
|
JobButtonForm,
|
|
20
20
|
JobHookForm,
|
|
21
|
-
RelationshipModelFormMixin,
|
|
22
|
-
StatusModelBulkEditFormMixin,
|
|
23
|
-
StatusModelFilterFormMixin,
|
|
24
|
-
TagsBulkEditFormMixin,
|
|
25
21
|
WebhookForm,
|
|
26
22
|
)
|
|
27
23
|
from nautobot.extras.models import (
|
|
@@ -1095,29 +1091,30 @@ class WebhookFormTestCase(TestCase):
|
|
|
1095
1091
|
)
|
|
1096
1092
|
|
|
1097
1093
|
|
|
1094
|
+
@skip(reason="Skipping until we have items that need to be deprecated again.")
|
|
1098
1095
|
class DeprecatedAliasesTestCase(TestCase):
|
|
1099
1096
|
"""Test that deprecated class names still exist, but report a DeprecationWarning when used."""
|
|
1100
1097
|
|
|
1101
1098
|
def test_deprecated_form_mixin_classes(self):
|
|
1102
1099
|
# Importing these mixin classes doesn't directly warn, but subclassing them does.
|
|
1103
|
-
from nautobot.extras.forms import CustomFieldBulkCreateForm
|
|
1104
|
-
from nautobot.extras.forms.mixins import (
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
)
|
|
1100
|
+
# from nautobot.extras.forms import CustomFieldBulkCreateForm
|
|
1101
|
+
# from nautobot.extras.forms.mixins import (
|
|
1102
|
+
# AddRemoveTagsForm,
|
|
1103
|
+
# CustomFieldBulkEditForm,
|
|
1104
|
+
# CustomFieldModelForm,
|
|
1105
|
+
# RelationshipModelForm,
|
|
1106
|
+
# StatusBulkEditFormMixin,
|
|
1107
|
+
# StatusFilterFormMixin,
|
|
1108
|
+
# )
|
|
1112
1109
|
|
|
1113
1110
|
for deprecated_form_class, replacement_form_class in (
|
|
1114
|
-
(AddRemoveTagsForm, TagsBulkEditFormMixin),
|
|
1115
|
-
(CustomFieldBulkEditForm, CustomFieldModelBulkEditFormMixin),
|
|
1116
|
-
(CustomFieldBulkCreateForm, CustomFieldModelBulkEditFormMixin),
|
|
1117
|
-
(CustomFieldModelForm, CustomFieldModelFormMixin),
|
|
1118
|
-
(RelationshipModelForm, RelationshipModelFormMixin),
|
|
1119
|
-
(StatusBulkEditFormMixin, StatusModelBulkEditFormMixin),
|
|
1120
|
-
(StatusFilterFormMixin, StatusModelFilterFormMixin),
|
|
1111
|
+
# (AddRemoveTagsForm, TagsBulkEditFormMixin),
|
|
1112
|
+
# (CustomFieldBulkEditForm, CustomFieldModelBulkEditFormMixin),
|
|
1113
|
+
# (CustomFieldBulkCreateForm, CustomFieldModelBulkEditFormMixin),
|
|
1114
|
+
# (CustomFieldModelForm, CustomFieldModelFormMixin),
|
|
1115
|
+
# (RelationshipModelForm, RelationshipModelFormMixin),
|
|
1116
|
+
# (StatusBulkEditFormMixin, StatusModelBulkEditFormMixin),
|
|
1117
|
+
# (StatusFilterFormMixin, StatusModelFilterFormMixin),
|
|
1121
1118
|
):
|
|
1122
1119
|
with self.subTest(msg=f"Replace {deprecated_form_class.__name__} with {replacement_form_class.__name__}"):
|
|
1123
1120
|
# Subclassing the deprecated class should raise a DeprecationWarning
|
|
@@ -16,7 +16,7 @@ from django.core.exceptions import ValidationError
|
|
|
16
16
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
|
17
17
|
from django.core.management import call_command
|
|
18
18
|
from django.core.management.base import CommandError
|
|
19
|
-
from django.test import override_settings
|
|
19
|
+
from django.test import override_settings, tag
|
|
20
20
|
from django.test.client import RequestFactory
|
|
21
21
|
from django.utils import timezone
|
|
22
22
|
|
|
@@ -286,6 +286,7 @@ register_jobs(BadJob)
|
|
|
286
286
|
# Clean up back to normal behavior
|
|
287
287
|
get_jobs(reload=True)
|
|
288
288
|
|
|
289
|
+
@tag("example_app")
|
|
289
290
|
def test_app_dynamic_jobs(self):
|
|
290
291
|
"""
|
|
291
292
|
Test that get_job() correctly reloads dynamic jobs when `NautobotAppConfig.provides_dynamic_jobs` is True.
|
|
@@ -645,6 +646,26 @@ class JobTransactionTest(TransactionTestCase):
|
|
|
645
646
|
self.assertFalse(logs.filter(message="I should NOT be logged to the database").exists())
|
|
646
647
|
self.assertTrue(logs.filter(message="I should be logged to the database").exists())
|
|
647
648
|
|
|
649
|
+
def test_log_counts_by_level(self):
|
|
650
|
+
"""
|
|
651
|
+
Test that related JobLogEntry counts are stored for JobResult list summary.
|
|
652
|
+
"""
|
|
653
|
+
module = "log_counts_by_level"
|
|
654
|
+
name = "TestLogCountsByLevel"
|
|
655
|
+
job_result = create_job_result_and_run_job(module, name)
|
|
656
|
+
|
|
657
|
+
self.assertGreater(job_result.job_log_entries.count(), 0)
|
|
658
|
+
self.assertIsNotNone(job_result.debug_log_count)
|
|
659
|
+
self.assertEqual(job_result.debug_log_count, 0)
|
|
660
|
+
self.assertIsNotNone(job_result.success_log_count)
|
|
661
|
+
self.assertEqual(job_result.success_log_count, 1)
|
|
662
|
+
self.assertIsNotNone(job_result.info_log_count)
|
|
663
|
+
self.assertEqual(job_result.info_log_count, 3)
|
|
664
|
+
self.assertIsNotNone(job_result.warning_log_count)
|
|
665
|
+
self.assertEqual(job_result.warning_log_count, 2)
|
|
666
|
+
self.assertIsNotNone(job_result.error_log_count)
|
|
667
|
+
self.assertEqual(job_result.error_log_count, 3)
|
|
668
|
+
|
|
648
669
|
def test_object_vars(self):
|
|
649
670
|
"""
|
|
650
671
|
Test that Object variable fields behave as expected.
|
|
@@ -1261,10 +1282,10 @@ class JobHookTransactionTest(TransactionTestCase): # TODO: BaseModelTestCase mi
|
|
|
1261
1282
|
status = models.Status.objects.get_for_model(Location).first()
|
|
1262
1283
|
loc = Location.objects.create(name="Test Job Hook Location 1", location_type=self.location_type, status=status)
|
|
1263
1284
|
models.ObjectChange.objects.all().delete()
|
|
1264
|
-
|
|
1265
|
-
|
|
1285
|
+
tag_instance = models.Tag.objects.create(name="A Test Tag")
|
|
1286
|
+
tag_instance.content_types.add(ContentType.objects.get_for_model(Location))
|
|
1266
1287
|
with web_request_context(user=self.user):
|
|
1267
|
-
loc.tags.add(
|
|
1288
|
+
loc.tags.add(tag_instance)
|
|
1268
1289
|
job_result = models.JobResult.objects.filter(job_model=self.job_model).first()
|
|
1269
1290
|
self.assertIsNotNone(job_result)
|
|
1270
1291
|
expected_log_messages = [
|
|
@@ -118,6 +118,7 @@ class CustomFieldDataMigrationTest(NautobotDataMigrationTest):
|
|
|
118
118
|
self.assertEqual(cf_1.key, "a123_main_ave")
|
|
119
119
|
self.assertEqual(cf_2.key, "a_456_main_ave")
|
|
120
120
|
|
|
121
|
+
@tag("example_app")
|
|
121
122
|
@skip("Something bad is happening with the test data, suspecting bad merge")
|
|
122
123
|
def test_custom_field_data_populated_correctly(self):
|
|
123
124
|
location_0 = self.location.objects.get(name="Test Location 1")
|
|
@@ -4,7 +4,6 @@ import shutil
|
|
|
4
4
|
import tempfile
|
|
5
5
|
from unittest import expectedFailure, mock
|
|
6
6
|
import uuid
|
|
7
|
-
import warnings
|
|
8
7
|
from zoneinfo import ZoneInfo
|
|
9
8
|
|
|
10
9
|
from django.conf import settings
|
|
@@ -15,8 +14,7 @@ from django.core.exceptions import ValidationError
|
|
|
15
14
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
|
16
15
|
from django.db.models import ProtectedError
|
|
17
16
|
from django.db.utils import IntegrityError
|
|
18
|
-
from django.test import override_settings
|
|
19
|
-
from django.test.utils import isolate_apps
|
|
17
|
+
from django.test import override_settings, tag
|
|
20
18
|
from django.utils.timezone import get_default_timezone, now
|
|
21
19
|
from django_celery_beat.tzcrontab import TzAwareCrontab
|
|
22
20
|
from git import GitCommandError
|
|
@@ -29,6 +27,7 @@ from nautobot.core.testing import TestCase
|
|
|
29
27
|
from nautobot.core.testing.models import ModelTestCases
|
|
30
28
|
from nautobot.dcim.models import (
|
|
31
29
|
Device,
|
|
30
|
+
DeviceFamily,
|
|
32
31
|
DeviceType,
|
|
33
32
|
Location,
|
|
34
33
|
LocationType,
|
|
@@ -90,7 +89,6 @@ from nautobot.extras.models import (
|
|
|
90
89
|
Team,
|
|
91
90
|
Webhook,
|
|
92
91
|
)
|
|
93
|
-
from nautobot.extras.models.statuses import StatusModel
|
|
94
92
|
from nautobot.extras.registry import registry
|
|
95
93
|
from nautobot.extras.secrets.exceptions import SecretParametersError, SecretProviderError, SecretValueNotFoundError
|
|
96
94
|
from nautobot.extras.tests.git_helper import create_and_populate_git_repository
|
|
@@ -103,8 +101,6 @@ from nautobot.virtualization.models import (
|
|
|
103
101
|
VirtualMachine,
|
|
104
102
|
)
|
|
105
103
|
|
|
106
|
-
from example_app.jobs import ExampleJob
|
|
107
|
-
|
|
108
104
|
User = get_user_model()
|
|
109
105
|
|
|
110
106
|
|
|
@@ -146,12 +142,12 @@ class ApprovalWorkflowTest(ModelTestCases.BaseModelTestCase):
|
|
|
146
142
|
cls.approval_workflow_definition = ApprovalWorkflowDefinition.objects.create(
|
|
147
143
|
name="Approval Workflow with Three Stages",
|
|
148
144
|
model_content_type=cls.scheduledjob_ct,
|
|
149
|
-
|
|
145
|
+
weight=1,
|
|
150
146
|
)
|
|
151
147
|
# Create three stages of the Approval Workflow Definition
|
|
152
148
|
cls.approval_workflow_stage_definition_1 = ApprovalWorkflowStageDefinition.objects.create(
|
|
153
149
|
approval_workflow_definition=cls.approval_workflow_definition,
|
|
154
|
-
|
|
150
|
+
sequence=100,
|
|
155
151
|
name="Approval Workflow Stage Definition 1",
|
|
156
152
|
min_approvers=1,
|
|
157
153
|
denial_message="Stage 1 Denial Message",
|
|
@@ -159,7 +155,7 @@ class ApprovalWorkflowTest(ModelTestCases.BaseModelTestCase):
|
|
|
159
155
|
)
|
|
160
156
|
cls.approval_workflow_stage_definition_2 = ApprovalWorkflowStageDefinition.objects.create(
|
|
161
157
|
approval_workflow_definition=cls.approval_workflow_definition,
|
|
162
|
-
|
|
158
|
+
sequence=200,
|
|
163
159
|
name="Approval Workflow Stage Definition 2",
|
|
164
160
|
min_approvers=2,
|
|
165
161
|
denial_message="Stage 2 Denial Message",
|
|
@@ -167,7 +163,7 @@ class ApprovalWorkflowTest(ModelTestCases.BaseModelTestCase):
|
|
|
167
163
|
)
|
|
168
164
|
cls.approval_workflow_stage_definition_3 = ApprovalWorkflowStageDefinition.objects.create(
|
|
169
165
|
approval_workflow_definition=cls.approval_workflow_definition,
|
|
170
|
-
|
|
166
|
+
sequence=300,
|
|
171
167
|
name="Approval Workflow Stage Definition 3",
|
|
172
168
|
min_approvers=2,
|
|
173
169
|
denial_message="Stage 3 Denial Message",
|
|
@@ -228,7 +224,7 @@ class ApprovalWorkflowTest(ModelTestCases.BaseModelTestCase):
|
|
|
228
224
|
"""
|
|
229
225
|
Test the active_stage property of the ApprovalWorkflow model.
|
|
230
226
|
"""
|
|
231
|
-
# Test that the active stage is the one with the lowest
|
|
227
|
+
# Test that the active stage is the one with the lowest sequence when all stages are pending
|
|
232
228
|
self.assertEqual(self.approval_workflow.active_stage, self.approval_workflow_stage_1)
|
|
233
229
|
# Test that the active stage is the second stage when the first stage is approved
|
|
234
230
|
self.approval_workflow_stage_1_response_1.state = ApprovalWorkflowStateChoices.APPROVED
|
|
@@ -323,7 +319,7 @@ class ApprovalWorkflowTest(ModelTestCases.BaseModelTestCase):
|
|
|
323
319
|
approval_workflow_definition = ApprovalWorkflowDefinition.objects.create(
|
|
324
320
|
name="Scheduled Job Approval Workflow",
|
|
325
321
|
model_content_type=scheduled_job_ct,
|
|
326
|
-
|
|
322
|
+
weight=2,
|
|
327
323
|
)
|
|
328
324
|
approval_workflow = ApprovalWorkflow(
|
|
329
325
|
approval_workflow_definition=approval_workflow_definition,
|
|
@@ -682,8 +678,11 @@ class ConfigContextTest(ModelTestCases.BaseModelTestCase):
|
|
|
682
678
|
|
|
683
679
|
@classmethod
|
|
684
680
|
def setUpTestData(cls):
|
|
685
|
-
manufacturer = Manufacturer.objects.first()
|
|
686
|
-
cls.
|
|
681
|
+
cls.manufacturer = Manufacturer.objects.first()
|
|
682
|
+
cls.devicefamily = DeviceFamily.objects.create(name="Device Family 1")
|
|
683
|
+
cls.devicetype = DeviceType.objects.create(
|
|
684
|
+
manufacturer=cls.manufacturer, model="Device Type 1", device_family=cls.devicefamily
|
|
685
|
+
)
|
|
687
686
|
cls.devicerole = Role.objects.get_for_model(Device).first()
|
|
688
687
|
root_location_type = LocationType.objects.create(name="Root Location Type")
|
|
689
688
|
parent_location_type = LocationType.objects.create(name="Parent Location Type", parent=root_location_type)
|
|
@@ -1222,6 +1221,38 @@ class ConfigContextTest(ModelTestCases.BaseModelTestCase):
|
|
|
1222
1221
|
self.assertNotIn("cluster_group_2", context.keys())
|
|
1223
1222
|
self.assertNotIn("cluster_group_12", context.keys())
|
|
1224
1223
|
|
|
1224
|
+
def test_device_family_context(self):
|
|
1225
|
+
"""
|
|
1226
|
+
A config context assigned to the device's DeviceFamily is included in get_config_context().
|
|
1227
|
+
"""
|
|
1228
|
+
|
|
1229
|
+
# Create a Family-level context
|
|
1230
|
+
cc_family = ConfigContext.objects.create(
|
|
1231
|
+
name="Device Family 1",
|
|
1232
|
+
weight=100,
|
|
1233
|
+
data={
|
|
1234
|
+
"device_family": "Device Family 1",
|
|
1235
|
+
},
|
|
1236
|
+
)
|
|
1237
|
+
cc_family.device_families.add(self.devicefamily)
|
|
1238
|
+
ctx1 = self.device.get_config_context()
|
|
1239
|
+
|
|
1240
|
+
# Create a second device for a negative test and verify that it does NOT receive the family context
|
|
1241
|
+
device_type2 = DeviceType.objects.create(manufacturer=self.manufacturer, model="Device Type2")
|
|
1242
|
+
device2 = Device.objects.create(
|
|
1243
|
+
name="Device 2",
|
|
1244
|
+
location=self.location,
|
|
1245
|
+
tenant=self.tenant,
|
|
1246
|
+
platform=self.platform,
|
|
1247
|
+
role=self.devicerole,
|
|
1248
|
+
status=self.device_status,
|
|
1249
|
+
device_type=device_type2,
|
|
1250
|
+
)
|
|
1251
|
+
ctx2 = device2.get_config_context()
|
|
1252
|
+
|
|
1253
|
+
self.assertEqual(ctx1.get("device_family"), "Device Family 1")
|
|
1254
|
+
self.assertEqual(ctx2.get("device_family"), None)
|
|
1255
|
+
|
|
1225
1256
|
|
|
1226
1257
|
class ConfigContextSchemaTestCase(ModelTestCases.BaseModelTestCase):
|
|
1227
1258
|
"""
|
|
@@ -1961,6 +1992,7 @@ class GitRepositoryTest(ModelTestCases.BaseModelTestCase):
|
|
|
1961
1992
|
shutil.rmtree(self.tempdir.name, ignore_errors=True)
|
|
1962
1993
|
|
|
1963
1994
|
|
|
1995
|
+
@tag("example_app")
|
|
1964
1996
|
class JobModelTest(ModelTestCases.BaseModelTestCase):
|
|
1965
1997
|
"""
|
|
1966
1998
|
Tests for the `Job` model class.
|
|
@@ -1976,6 +2008,8 @@ class JobModelTest(ModelTestCases.BaseModelTestCase):
|
|
|
1976
2008
|
cls.app_job = JobModel.objects.get(job_class_name="ExampleJob")
|
|
1977
2009
|
|
|
1978
2010
|
def test_job_class(self):
|
|
2011
|
+
from example_app.jobs import ExampleJob
|
|
2012
|
+
|
|
1979
2013
|
self.assertIsNotNone(self.local_job.job_class)
|
|
1980
2014
|
self.assertEqual(self.local_job.job_class.description, "Validate job import")
|
|
1981
2015
|
|
|
@@ -3495,31 +3529,15 @@ class StatusTest(ModelTestCases.BaseModelTestCase):
|
|
|
3495
3529
|
self.status.save()
|
|
3496
3530
|
self.assertEqual(str(self.status), test)
|
|
3497
3531
|
|
|
3498
|
-
@isolate_apps("nautobot.extras.tests")
|
|
3499
|
-
def test_deprecated_mixin_class(self):
|
|
3500
|
-
"""Test that inheriting from StatusModel raises a DeprecationWarning."""
|
|
3501
|
-
with warnings.catch_warnings(record=True) as warn_list:
|
|
3502
|
-
warnings.simplefilter("always")
|
|
3503
|
-
|
|
3504
|
-
class MyModel(StatusModel): # pylint: disable=unused-variable
|
|
3505
|
-
pass
|
|
3506
|
-
|
|
3507
|
-
self.assertEqual(len(warn_list), 1)
|
|
3508
|
-
warning = warn_list[0]
|
|
3509
|
-
self.assertTrue(issubclass(warning.category, DeprecationWarning))
|
|
3510
|
-
self.assertIn("StatusModel is deprecated", str(warning))
|
|
3511
|
-
self.assertIn("Instead of deriving MyModel from StatusModel", str(warning))
|
|
3512
|
-
self.assertIn("please directly declare `status = StatusField(...)` on your model instead", str(warning))
|
|
3513
|
-
|
|
3514
3532
|
|
|
3515
3533
|
class TagTest(ModelTestCases.BaseModelTestCase):
|
|
3516
3534
|
model = Tag
|
|
3517
3535
|
|
|
3518
3536
|
def test_create_tag_unicode(self):
|
|
3519
|
-
|
|
3520
|
-
|
|
3537
|
+
instance = Tag(name="Testing Unicode: 台灣")
|
|
3538
|
+
instance.save()
|
|
3521
3539
|
|
|
3522
|
-
self.assertEqual(
|
|
3540
|
+
self.assertEqual(instance.name, "Testing Unicode: 台灣")
|
|
3523
3541
|
|
|
3524
3542
|
|
|
3525
3543
|
class JobLogEntryTest(TestCase): # TODO: change to BaseModelTestCase
|