lfsx-server 0.30.0

A fast, lightweight, secure Git LFS server
Documentation
use super::*;
use crate::locks::Owner;

fn lock(id: &str) -> Lock {
    Lock {
        id: id.to_owned(),
        path: format!("Assets/{id}.psd"),
        locked_at: "2026-08-15T00:00:00Z".to_owned(),
        owner: Owner {
            name: "writer".to_owned(),
        },
    }
}

fn locks(count: usize) -> Vec<Lock> {
    (0..count).map(|n| lock(&format!("{n:04}"))).collect()
}

fn ids(page: &Page) -> Vec<&str> {
    page.locks.iter().map(|lock| lock.id.as_str()).collect()
}

#[test]
fn a_short_list_comes_back_whole_with_no_cursor() {
    let page = paginate(locks(3), None, None);

    assert_eq!(ids(&page), ["0000", "0001", "0002"]);
    assert!(
        page.next_cursor.is_empty(),
        "an empty cursor is what tells the client it has the whole list"
    );
}

#[test]
fn a_limit_is_honoured_and_says_where_to_resume() {
    let page = paginate(locks(10), None, Some(4));

    assert_eq!(ids(&page), ["0000", "0001", "0002", "0003"]);
    assert_eq!(page.next_cursor, "0003");
}

#[test]
fn the_cursor_resumes_after_the_lock_it_names() {
    let first = paginate(locks(10), None, Some(4));
    let second = paginate(locks(10), Some(&first.next_cursor), Some(4));

    assert_eq!(ids(&second), ["0004", "0005", "0006", "0007"]);
    assert_eq!(second.next_cursor, "0007");
}

#[test]
fn the_last_page_closes_the_walk() {
    let page = paginate(locks(10), Some("0007"), Some(4));

    assert_eq!(ids(&page), ["0008", "0009"]);
    assert!(
        page.next_cursor.is_empty(),
        "a cursor on the last page sends the client round again for nothing"
    );
}

#[test]
fn a_lock_released_between_pages_does_not_lose_the_ones_after_it() {
    let mut remaining = locks(10);
    remaining.retain(|lock| lock.id != "0004");

    let page = paginate(remaining, Some("0003"), Some(4));

    assert_eq!(
        ids(&page),
        ["0005", "0006", "0007", "0008"],
        "the cursor is a position in the ordering, not an index, so releasing a lock mid-walk \
         skips it rather than shifting everything after it out of view"
    );
}

#[test]
fn an_unreasonable_limit_is_brought_back_to_one_this_server_will_serve() {
    assert_eq!(paginate(locks(5), None, Some(0)).locks.len(), 1);
    assert_eq!(paginate(locks(5), None, Some(usize::MAX)).locks.len(), 5);
    assert_eq!(
        paginate(locks(2000), None, Some(usize::MAX)).locks.len(),
        MAX
    );
}

#[test]
fn the_order_does_not_depend_on_how_the_directory_was_read() {
    let mut shuffled = locks(6);
    shuffled.reverse();

    assert_eq!(
        ids(&paginate(shuffled, None, Some(3))),
        ["0000", "0001", "0002"],
        "a cursor is only meaningful against a stable order, and a directory listing is not one"
    );
}