Files
esp-idf/components/esp_eth/test_apps/README.md
Ondrej Kosta d3d5b239fb feat(esp_eth): Ethernet test refactor
ETH tests use setUp-tearDown to init/deinit resources
2026-02-25 08:42:49 +01:00

181 lines
9.0 KiB
Markdown

| Supported Targets | ESP32 | ESP32-P4 |
| ----------------- | ----- | -------- |
# Ethernet Test
This test app is used to test Ethernet MAC behavior with different chips.
## Prerequisites
Install third part Python packages:
```bash
pip install scapy
```
## Chip-Specific Configuration
Different Ethernet chips may have deviations from the standard behavior or may not support certain features. To accommodate these chip-specific differences, the test framework provides Kconfig options that allow disabling or modifying specific tests that are incompatible with certain chips.
For example, some chips may not support 10 Mbps loopback mode, or may have known errata that require workarounds. These Kconfig options are defined in `main/Kconfig.projbuild` and can be configured through the ESP-IDF menuconfig system to adjust test behavior for the specific chip under test.
Refer to `main/Kconfig.projbuild` for the complete list of available configuration options and their descriptions.
## Test Framework Overview
The test framework provides common initialization and helper functions through `esp_eth_test_utils.h` and `esp_eth_test_utils.c`. These modules handle Ethernet initialization, event registration, and resource management automatically using Unity's `setUp()` and `tearDown()` functions.
### Unity setUp() and tearDown()
The `setUp()` function automatically performs the following initialization before each test case:
1. **Sets up event handling** (creates event group and default event loop)
2. **Initializes the Ethernet driver** by calling `esp_eth_test_eth_init()` (uses Ethernet init component by default, can be customized - see [Customizing Ethernet Initialization](#customizing-ethernet-initialization) section below)
3. **Optionally sets up esp-netif** if the `[esp-netif]` marker is used (see [Markers](#test-markers) section below)
4. **Registers event handlers**:
- `eth_test_default_event_handler()` for ETH_EVENT events (ETHERNET_EVENT_START, ETHERNET_EVENT_STOP, ETHERNET_EVENT_CONNECTED, ETHERNET_EVENT_DISCONNECTED)
- `eth_test_got_ip_event_handler()` for IP_EVENT_ETH_GOT_IP events (only when `[esp-netif]` marker is used)
The `tearDown()` function automatically performs cleanup after each test case:
1. **Frees all allocated memory** tracked by the test framework
2. **Unregisters event handlers**
3. **Stops and deinitializes the Ethernet driver** by calling `esp_eth_test_eth_deinit()` (uses Ethernet init component by default, can be customized - see [Customizing Ethernet Initialization](#customizing-ethernet-initialization) section below)
4. **Destroys the event loop and event group**
### Customizing Ethernet Initialization
By default, the test framework initializes Ethernet using the **Ethernet init component**. This provides initialization of Ethernet hardware based on Kconfig settings.
For test cases that require custom Ethernet initialization (e.g., chip not supported by Ethernet init component, specific MAC/PHY configurations, multiple Ethernet ports, or custom hardware setup), you can override the weak functions:
- **`esp_eth_test_eth_init(esp_eth_handle_t *eth_handle)`**: Override this function to provide custom Ethernet initialization. The function should initialize the Ethernet driver and return the handle via the `eth_handle` parameter.
> [!IMPORTANT]
> Initialization function must print DUT PHY identification string as it is expected by `pytest` script. The PHY identification message must be in the following format:
> ```c
> printf("DUT PHY: %s", my_phy_str);
>```
- **`esp_eth_test_eth_deinit(esp_eth_handle_t eth_handle)`**: Override this function to provide custom Ethernet deinitialization. The function should clean up the Ethernet driver resources.
### Test Markers
Test cases can use markers in their Unity test identifiers to control initialization behavior:
#### `[esp-netif]` Marker
When this marker is included in the test case identifier, `setUp()` will additionally initialize TCP/IP stack by:
- Creating an ESP-NETIF interface using `ESP_NETIF_DEFAULT_ETH()` configuration
- Attaching the Ethernet driver to the netif using `esp_eth_new_netif_glue()`
- Registering the `eth_test_got_ip_event_handler()` for IP_EVENT_ETH_GOT_IP events
**Example:**
```c
TEST_CASE("ethernet dhcp test", "[ethernet][esp-netif]")
{
esp_eth_handle_t eth_handle = eth_test_get_eth_handle();
EventGroupHandle_t eth_event_group = eth_test_get_default_event_group();
esp_netif_t *netif = eth_test_get_netif(); // Valid when [esp-netif] is used
// Test code using TCP/IP stack...
}
```
#### `[skip_setup_teardown]` Marker
When this marker is included, `setUp()` and `tearDown()` will skip all automatic initialization and cleanup. This allows the test to perform its own custom initialization and cleanup procedures.
> [!IMPORTANT]
> When using this marker, you must manually:
> - Register event handlers using `eth_test_default_event_handler()` and/or `eth_test_got_ip_event_handler()`
> - Initialize and deinitialize all resources except for memory allocated by `eth_test_alloc()`
> [!NOTE]
> Memory allocated through `eth_test_alloc()` is automatically freed by `tearDown()` even when using this marker.
**Example:**
```c
TEST_CASE("internal emac interrupt priority", "[esp_emac][skip_setup_teardown]")
{
// Manual initialization
EventGroupHandle_t eth_event_group = xEventGroupCreate();
TEST_ESP_OK(esp_event_loop_create_default());
// Register handlers manually if needed
// ... custom test code ...
}
```
### Helper Functions
#### Getting Initialized Handles
- **`eth_test_get_eth_handle()`**: Returns the Ethernet handle initialized by `setUp()`. Returns `NULL` if initialization failed or if `[skip_setup_teardown]` marker is used.
- **`eth_test_get_default_event_group()`**: Returns the event group handle created by `setUp()`. Use this to wait for Ethernet events using `xEventGroupWaitBits()` with the predefined bits (ETH_START_BIT, ETH_STOP_BIT, ETH_CONNECT_BIT, ETH_GOT_IP_BIT).
- **`eth_test_get_netif()`**: Returns the ESP-NETIF handle initialized by `setUp()`. **Only valid when `[esp-netif]` marker is used**, otherwise returns `NULL`.
#### PHY Register Manipulation
- **`eth_test_set_phy_reg_bits()`**: Sets specific bits in a PHY register with retry logic. Useful for configuring PHY behavior during tests.
- **`eth_test_clear_phy_reg_bits()`**: Clears specific bits in a PHY register with retry logic.
Both functions include automatic retry logic with configurable maximum attempts and delays between attempts.
#### Memory Management
- **`eth_test_alloc(size)`**: Allocates memory from the heap. The framework automatically tracks all allocations and frees them in `tearDown()`. Maximum of `MAX_HEAP_ALLOCATION_POINTERS` (20) allocations are supported.
- **`eth_test_free(ptr)`**: Frees a specific allocation. Generally not needed as `tearDown()` automatically frees all tracked allocations.
- **`eth_test_free_all()`**: Frees all tracked allocations. Called automatically by `tearDown()`.
#### Event Handlers
- **`eth_test_default_event_handler()`**: Default handler for ETH_EVENT events. Automatically registered by `setUp()` unless `[skip_setup_teardown]` is used. Sets event bits in the event group for:
- ETHERNET_EVENT_START → ETH_START_BIT
- ETHERNET_EVENT_STOP → ETH_STOP_BIT
- ETHERNET_EVENT_CONNECTED → ETH_CONNECT_BIT
- **`eth_test_got_ip_event_handler()`**: Handler for IP_EVENT_ETH_GOT_IP events. Automatically registered by `setUp()` when `[esp-netif]` marker is used. Sets ETH_GOT_IP_BIT in the event group and logs IP configuration.
### Usage Example
```c
TEST_CASE("ethernet basic test", "[ethernet][esp-netif]")
{
// Get handles initialized by setUp()
esp_eth_handle_t eth_handle = eth_test_get_eth_handle();
EventGroupHandle_t eth_event_group = eth_test_get_default_event_group();
esp_netif_t *netif = eth_test_get_netif();
EventBits_t bits = 0;
// Start Ethernet driver
TEST_ESP_OK(esp_eth_start(eth_handle));
// Wait for Ethernet to start
bits = xEventGroupWaitBits(eth_event_group, ETH_START_BIT, true, true,
pdMS_TO_TICKS(ETH_START_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_START_BIT) == ETH_START_BIT);
// Wait for link connection
bits = xEventGroupWaitBits(eth_event_group, ETH_CONNECT_BIT, true, true,
pdMS_TO_TICKS(ETH_CONNECT_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_CONNECT_BIT) == ETH_CONNECT_BIT);
// Wait for IP address (only when [esp-netif] is used)
bits = xEventGroupWaitBits(eth_event_group, ETH_GOT_IP_BIT, true, true,
pdMS_TO_TICKS(ETH_GET_IP_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_GOT_IP_BIT) == ETH_GOT_IP_BIT);
// Test code here...
// Stop Ethernet driver
TEST_ESP_OK(esp_eth_stop(eth_handle));
// Wait for stop event
bits = xEventGroupWaitBits(eth_event_group, ETH_STOP_BIT, true, true,
pdMS_TO_TICKS(ETH_STOP_TIMEOUT_MS));
TEST_ASSERT((bits & ETH_STOP_BIT) == ETH_STOP_BIT);
// tearDown() will automatically clean up everything
}
```