apeirogond 0.27.0

Daemon for Apeirogon, a cross-platform software KVM
// SPDX-License-Identifier: GPL-3.0-or-later

use std::net::{Ipv4Addr, SocketAddr};

use super::*;
use crate::layout_store::LayoutStore;

#[tokio::test]
async fn receive_newer_peer_layout_replaces_and_persists() {
    // Arrange
    let dir = tempfile::tempdir().unwrap();
    let mut daemon = Daemon::load(dir.path(), SocketAddr::from((Ipv4Addr::LOCALHOST, 0))).unwrap();
    let peer = MachineId::try_from(&[1; MachineId::LEN][..]).unwrap();
    let incoming = Layout::empty(peer)
        .edit(
            vec![Placement {
                id: peer,
                x: 0,
                y: 0,
                width: 100,
                height: 100,
                blocked: 0,
            }],
            peer,
        )
        .unwrap();

    // Act
    daemon
        .receive(Envelope {
            body: Some(Body::Layout(incoming.to_proto())),
        })
        .unwrap();

    // Assert
    assert_eq!(daemon.layout.state, incoming);
    let restored = LayoutStore::load(&dir.path().join("layout.pb"), daemon.identity.machine_id);
    assert_eq!(restored.state, incoming);
    assert_eq!(daemon.layout_info().placed[0].name, "Unpaired machine");
}

#[tokio::test]
async fn receive_invalid_layout_ignores_without_link_error() {
    // Arrange
    let dir = tempfile::tempdir().unwrap();
    let mut daemon = Daemon::load(dir.path(), SocketAddr::from((Ipv4Addr::LOCALHOST, 0))).unwrap();
    let before = daemon.layout.state.clone();
    let mut invalid = before.to_proto();
    invalid.version = u64::MAX;
    invalid.machines.push(v1::MachineRect {
        id: daemon.identity.machine_id.as_bytes().to_vec(),
        ..v1::MachineRect::default()
    });

    // Act
    let result = daemon.receive(Envelope {
        body: Some(Body::Layout(invalid)),
    });

    // Assert
    assert!(
        result.is_ok(),
        "the run loop closes a link only on receive errors"
    );
    assert_eq!(daemon.layout.state, before);
    assert!(!dir.path().join("layout.pb").exists());
}

#[test]
fn load_saturated_layout_restarts_version_and_keeps_placements() {
    // Arrange
    let dir = tempfile::tempdir().unwrap();
    let path = dir.path().join("layout.pb");
    let own = MachineId::try_from(&[1; MachineId::LEN][..]).unwrap();
    let placed = Layout::empty(own)
        .edit(
            vec![Placement {
                id: own,
                x: 0,
                y: 0,
                width: 100,
                height: 100,
                blocked: 0,
            }],
            own,
        )
        .unwrap();
    let mut saturated = placed.to_proto();
    saturated.version = u64::MAX;
    std::fs::write(&path, prost::Message::encode_to_vec(&saturated)).unwrap();

    // Act
    let restored = LayoutStore::load(&path, own);

    // Assert
    assert_eq!(restored.state.version(), 0);
    assert_eq!(restored.state.placements(), placed.placements());
}