Skip to content

Commit

Permalink
Check test configuration at runtime and on demand
Browse files Browse the repository at this point in the history
This cleans up the initial attempt of specifying the hardware ports to
be used for testing by:

    * Requiring the configuration environment variables only to be
      present when actually required by a test case

    * Evaluating these environment variables at runtime, eliminating the
      footgun that changing them does not trigger rebuilding the tests

    * No longer requiring to set dummy configuration variables when not
      running any hardware tests at all (like in CI).

The configuration environment variable prefix changes from
SERIALPORT_RS_TEST_ to SERIALPORT_TEST_ to match the crate name and not
the repository name.

The changes add two new dev dependencies which both look worth it:

    * The envconfig crate eliminates any need for custom error reporting
      about which environment variable is missing (which not comes for
      free when just using std::env::var)

    * The rstest crate conveniently allows to use test fixtures and
      supports parametrizing tests which will likely be used by the next
      test cases to come
  • Loading branch information
sirhcel authored and eldruin committed May 13, 2024
1 parent d6b92be commit b8a8d05
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 30 deletions.
4 changes: 0 additions & 4 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,6 @@ env:
PKG_CONFIG_ALLOW_CROSS: 1
# Deny warnings.
RUSTFLAGS: -D warnings
# Dummy ports for hardware tests. Keep in sync with other workflows (in
# ci.yaml).
SERIALPORT_RS_TEST_PORT_1: DUMMY_PORT_1
SERIALPORT_RS_TEST_PORT_2: DUMMY_PORT_2

jobs:
build:
Expand Down
5 changes: 0 additions & 5 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ on:
push:
workflow_dispatch:

env:
# Dummy ports for hardware tests. Keep in sync with workflows in build.yaml.
SERIALPORT_RS_TEST_PORT_1: DUMMY_PORT_1
SERIALPORT_RS_TEST_PORT_2: DUMMY_PORT_2

jobs:
# --------------------------------------------------------------------------
# LINT
Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ serde = { version = "1.0", features = ["derive"], optional = true }
[dev-dependencies]
assert_hex = "0.4.1"
clap = { version = "3.1.6", features = ["derive"] }
envconfig = "0.10.0"
rstest = { version = "0.12.0", default-features = false }

[features]
default = ["libudev"]
Expand Down
25 changes: 25 additions & 0 deletions tests/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Configuration for integration tests. This crate is about interacting with real serial ports and
// so some tests need actual hardware.

use envconfig::Envconfig;
use rstest::fixture;

// Configuration for tests requiring acutual hardware.
//
// For conveniently pulling this configuration into a test case as a parameter, you might want to
// use the test fixture [`hw_config`].
#[derive(Clone, Debug, Envconfig, Eq, PartialEq)]
pub struct HardwareConfig {
#[envconfig(from = "SERIALPORT_TEST_PORT_1")]
pub port_1: String,
#[envconfig(from = "SERIALPORT_TEST_PORT_2")]
pub port_2: String,
}

// Test fixture for conveniently pulling the actual hardware configuration into test cases.
//
// See [`fixture`](rstest::fixture) for details.
#[fixture]
pub fn hw_config() -> HardwareConfig {
HardwareConfig::init_from_env().unwrap()
}
48 changes: 27 additions & 21 deletions tests/test_serialport.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
//! Tests for the `SerialPort` trait.
#![cfg(unix)]

mod config;

use config::{hw_config, HardwareConfig};
use rstest::rstest;
use serialport::*;
use std::time::Duration;

const PORT_1: &str = env!("SERIALPORT_RS_TEST_PORT_1");
const PORT_2: &str = env!("SERIALPORT_RS_TEST_PORT_2");

#[test]
#[rstest]
#[cfg_attr(feature = "ignore-hardware-tests", ignore)]
fn test_listing_ports() {
let ports = serialport::available_ports().expect("No ports found!");
Expand All @@ -16,32 +17,34 @@ fn test_listing_ports() {
}
}

#[test]
#[rstest]
#[cfg_attr(feature = "ignore-hardware-tests", ignore)]
fn test_opening_found_ports() {
fn test_opening_found_ports(hw_config: HardwareConfig) {
// There is no guarantee that we even might open the ports returned by `available_ports`. But
// the ports we are using for testing shall be among them.
let ports = serialport::available_ports().unwrap();
assert!(ports.iter().any(|info| info.port_name == PORT_1));
assert!(ports.iter().any(|info| info.port_name == PORT_2));
assert!(ports.iter().any(|info| info.port_name == hw_config.port_1));
assert!(ports.iter().any(|info| info.port_name == hw_config.port_2));
}

#[test]
#[rstest]
#[cfg_attr(feature = "ignore-hardware-tests", ignore)]
fn test_opening_port() {
serialport::new(PORT_1, 9600).open().unwrap();
fn test_opening_port(hw_config: HardwareConfig) {
serialport::new(hw_config.port_1, 9600).open().unwrap();
}

#[test]
#[rstest]
#[cfg_attr(feature = "ignore-hardware-tests", ignore)]
fn test_opening_native_port() {
serialport::new(PORT_1, 9600).open_native().unwrap();
fn test_opening_native_port(hw_config: HardwareConfig) {
serialport::new(hw_config.port_1, 9600)
.open_native()
.unwrap();
}

#[test]
#[rstest]
#[cfg_attr(feature = "ignore-hardware-tests", ignore)]
fn test_configuring_ports() {
serialport::new(PORT_1, 9600)
fn test_configuring_ports(hw_config: HardwareConfig) {
serialport::new(hw_config.port_1, 9600)
.data_bits(DataBits::Five)
.flow_control(FlowControl::None)
.parity(Parity::None)
Expand All @@ -51,17 +54,20 @@ fn test_configuring_ports() {
.unwrap();
}

#[test]
#[rstest]
#[cfg_attr(feature = "ignore-hardware-tests", ignore)]
fn test_duplicating_port_config() {
let port1_config = serialport::new(PORT_1, 9600)
fn test_duplicating_port_config(hw_config: HardwareConfig) {
let port1_config = serialport::new(hw_config.port_1, 9600)
.data_bits(DataBits::Five)
.flow_control(FlowControl::None)
.parity(Parity::None)
.stop_bits(StopBits::One)
.timeout(Duration::from_millis(1));

let port2_config = port1_config.clone().path(PORT_2).baud_rate(115_200);
let port2_config = port1_config
.clone()
.path(hw_config.port_2)
.baud_rate(115_200);

let _port1 = port1_config.open().unwrap();
let _port1 = port2_config.open().unwrap();
Expand Down

0 comments on commit b8a8d05

Please sign in to comment.