1
use crate::{service::PrompterType, tests::TestServiceSetup};
2

            
3
4
async fn prompt_called_twice_error_impl(
4
    prompter_type: PrompterType,
5
) -> Result<(), Box<dyn std::error::Error>> {
6
12
    let setup = TestServiceSetup::plain_session(true).await?;
7
8
    setup.server.set_prompter_type(prompter_type).await;
8

            
9
    // Lock the collection to create a prompt scenario
10
4
    setup.lock_collection(&setup.collections[0]).await?;
11

            
12
    // Get a prompt path by calling unlock (which creates a prompt but doesn't
13
    // auto-trigger it)
14
16
    let (_unlocked, prompt_path) = setup
15
        .server
16
4
        .unlock(vec![setup.collections[0].inner().path().to_owned().into()])
17
12
        .await?;
18

            
19
    // Verify we got a prompt path
20
    assert!(!prompt_path.is_empty(), "Should have a prompt path");
21

            
22
    // Create a Prompt proxy manually
23
24
    let prompt = oo7::dbus::api::Prompt::new(&setup.client_conn, prompt_path.clone())
24
12
        .await?
25
        .unwrap();
26

            
27
    // First call to prompt() should succeed
28
12
    prompt.prompt(None).await?;
29

            
30
    // Give the prompt a moment to register the callback
31
8
    tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
32

            
33
    // Second call to prompt() should fail with "callback is ongoing already" error
34
    assert!(
35
        prompt.prompt(None).await.is_err(),
36
        "Second call to prompt() should fail"
37
    );
38
4
    Ok(())
39
}
40

            
41
#[cfg(any(feature = "gnome_native_crypto", feature = "gnome_openssl_crypto"))]
42
#[tokio::test]
43
async fn prompt_called_twice_error_gnome() -> Result<(), Box<dyn std::error::Error>> {
44
    prompt_called_twice_error_impl(PrompterType::GNOME).await
45
}
46

            
47
#[cfg(any(feature = "plasma_native_crypto", feature = "plasma_openssl_crypto"))]
48
#[tokio::test]
49
async fn prompt_called_twice_error_plasma() -> Result<(), Box<dyn std::error::Error>> {
50
    prompt_called_twice_error_impl(PrompterType::Plasma).await
51
}
52

            
53
#[cfg(any(feature = "gnome_native_crypto", feature = "gnome_openssl_crypto"))]
54
#[tokio::test]
55
async fn prompt_not_found_error() -> Result<(), Box<dyn std::error::Error>> {
56
    let setup = TestServiceSetup::plain_session(true).await?;
57

            
58
    // Lock the collection to create a prompt scenario
59
    setup.lock_collection(&setup.collections[0]).await?;
60

            
61
    // Create a prompt using server API
62
    let (_unlocked, prompt_path) = setup
63
        .server
64
        .unlock(vec![setup.collections[0].inner().path().to_owned().into()])
65
        .await?;
66

            
67
    assert!(!prompt_path.is_empty(), "Should have a prompt path");
68

            
69
    // Remove the prompt from the service before MockPrompter tries to process it
70
    setup.server.remove_prompt(&prompt_path).await;
71

            
72
    // Manually serve a callback to trigger the error path
73
    let callback = crate::gnome::prompter::GNOMEPrompterCallback::new(
74
        None,
75
        setup.server.clone(),
76
        prompt_path.clone(),
77
    )
78
    .await?;
79

            
80
    let callback_path = super::OwnedObjectPath::from(callback.path().clone());
81
    setup
82
        .server
83
        .object_server()
84
        .at(&callback_path, callback.clone())
85
        .await?;
86

            
87
    // Now call prompt_ready which should fail because the prompt doesn't exist
88
    let result = callback
89
        .prompt_ready(
90
            zbus::zvariant::Optional::from(None),
91
            crate::gnome::prompter::Properties::default(),
92
            "",
93
        )
94
        .await;
95

            
96
    assert!(result.is_err(), "Should fail when prompt doesn't exist");
97

            
98
    // Verify it's the specific error we expect
99
    assert!(
100
        matches!(result, Err(oo7::dbus::ServiceError::NoSuchObject(_))),
101
        "Should be NoSuchObject error"
102
    );
103

            
104
    Ok(())
105
}
106

            
107
#[tokio::test]
108
async fn dismiss_prompt_cleanup() -> Result<(), Box<dyn std::error::Error>> {
109
    let setup = TestServiceSetup::plain_session(true).await?;
110

            
111
    // Lock the collection to create a prompt scenario
112
    setup.lock_collection(&setup.collections[0]).await?;
113

            
114
    // Get a prompt path by calling unlock
115
    let (_unlocked, prompt_path) = setup
116
        .server
117
        .unlock(vec![setup.collections[0].inner().path().to_owned().into()])
118
        .await?;
119

            
120
    assert!(!prompt_path.is_empty(), "Should have a prompt path");
121

            
122
    // Verify prompt exists in service before dismissal
123
    let prompt_exists_before = setup.server.prompt(&prompt_path).await;
124
    assert!(
125
        prompt_exists_before.is_some(),
126
        "Prompt should exist in service before dismissal"
127
    );
128

            
129
    // Verify prompt is accessible via D-Bus
130
    let prompt = oo7::dbus::api::Prompt::new(&setup.client_conn, prompt_path.clone()).await?;
131
    assert!(
132
        prompt.is_some(),
133
        "Prompt should be accessible via D-Bus before dismissal"
134
    );
135

            
136
    // Dismiss the prompt
137
    prompt.unwrap().dismiss().await?;
138

            
139
    // Give it a moment to process the dismissal
140
    tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
141

            
142
    // Verify prompt is removed from service
143
    let prompt_exists_after = setup.server.prompt(&prompt_path).await;
144
    assert!(
145
        prompt_exists_after.is_none(),
146
        "Prompt should be removed from service after dismissal"
147
    );
148

            
149
    Ok(())
150
}