fxa_client/state_machine/internal_machines/
authenticating.rs1use super::{invalid_transition, Event, InternalStateMachine, State};
6use crate::{Error, FxaEvent, FxaState, Result};
7
8pub struct AuthenticatingStateMachine;
9
10use Event::*;
12use State::*;
13
14impl InternalStateMachine for AuthenticatingStateMachine {
15 fn initial_state(&self, event: FxaEvent) -> Result<State> {
16 match event {
17 FxaEvent::CompleteOAuthFlow { code, state } => Ok(CompleteOAuthFlow {
18 code: code.clone(),
19 state: state.clone(),
20 }),
21 FxaEvent::CancelOAuthFlow => Ok(Complete(FxaState::Disconnected)),
22 FxaEvent::BeginOAuthFlow { scopes, entrypoint } => {
25 Ok(State::BeginOAuthFlow { scopes, entrypoint })
26 }
27 FxaEvent::BeginPairingFlow {
28 pairing_url,
29 scopes,
30 entrypoint,
31 } => Ok(State::BeginPairingFlow {
32 pairing_url,
33 scopes,
34 entrypoint,
35 }),
36 e => Err(Error::InvalidStateTransition(format!(
37 "Authenticating -> {e}"
38 ))),
39 }
40 }
41
42 fn next_state(&self, state: State, event: Event) -> Result<State> {
43 Ok(match (state, event) {
44 (CompleteOAuthFlow { .. }, CompleteOAuthFlowSuccess) => InitializeDevice,
45 (CompleteOAuthFlow { .. }, CallError) => Complete(FxaState::Disconnected),
46 (InitializeDevice, InitializeDeviceSuccess) => Complete(FxaState::Connected),
47 (InitializeDevice, CallError) => Complete(FxaState::Disconnected),
48 (BeginOAuthFlow { .. }, BeginOAuthFlowSuccess { oauth_url }) => {
49 Complete(FxaState::Authenticating { oauth_url })
50 }
51 (BeginPairingFlow { .. }, BeginPairingFlowSuccess { oauth_url }) => {
52 Complete(FxaState::Authenticating { oauth_url })
53 }
54 (BeginOAuthFlow { .. }, CallError) => Complete(FxaState::Disconnected),
55 (BeginPairingFlow { .. }, CallError) => Complete(FxaState::Disconnected),
56 (state, event) => return invalid_transition(state, event),
57 })
58 }
59}
60
61#[cfg(test)]
62mod test {
63 use super::super::StateMachineTester;
64 use super::*;
65
66 #[test]
67 fn test_complete_oauth_flow() {
68 let mut tester = StateMachineTester::new(
69 AuthenticatingStateMachine,
70 FxaEvent::CompleteOAuthFlow {
71 code: "test-code".to_owned(),
72 state: "test-state".to_owned(),
73 },
74 );
75 assert_eq!(
76 tester.state,
77 CompleteOAuthFlow {
78 code: "test-code".to_owned(),
79 state: "test-state".to_owned(),
80 }
81 );
82 assert_eq!(
83 tester.peek_next_state(CallError),
84 Complete(FxaState::Disconnected)
85 );
86
87 tester.next_state(CompleteOAuthFlowSuccess);
88 assert_eq!(tester.state, InitializeDevice);
89 assert_eq!(
90 tester.peek_next_state(CallError),
91 Complete(FxaState::Disconnected)
92 );
93 assert_eq!(
94 tester.peek_next_state(InitializeDeviceSuccess),
95 Complete(FxaState::Connected)
96 );
97 }
98
99 #[test]
100 fn test_cancel_oauth_flow() {
101 let tester = StateMachineTester::new(AuthenticatingStateMachine, FxaEvent::CancelOAuthFlow);
102 assert_eq!(tester.state, Complete(FxaState::Disconnected));
103 }
104
105 #[test]
111 fn test_begin_oauth_flow() {
112 let tester = StateMachineTester::new(
113 AuthenticatingStateMachine,
114 FxaEvent::BeginOAuthFlow {
115 scopes: vec!["profile".to_owned()],
116 entrypoint: "test-entrypoint".to_owned(),
117 },
118 );
119 assert_eq!(
120 tester.state,
121 BeginOAuthFlow {
122 scopes: vec!["profile".to_owned()],
123 entrypoint: "test-entrypoint".to_owned(),
124 }
125 );
126 assert_eq!(
127 tester.peek_next_state(CallError),
128 Complete(FxaState::Disconnected)
129 );
130 assert_eq!(
131 tester.peek_next_state(BeginOAuthFlowSuccess {
132 oauth_url: "http://example.com/oauth-start".to_owned(),
133 }),
134 Complete(FxaState::Authenticating {
135 oauth_url: "http://example.com/oauth-start".to_owned(),
136 })
137 );
138 }
139
140 #[test]
142 fn test_begin_pairing_flow() {
143 let tester = StateMachineTester::new(
144 AuthenticatingStateMachine,
145 FxaEvent::BeginPairingFlow {
146 pairing_url: "https://example.com/pairing-url".to_owned(),
147 scopes: vec!["profile".to_owned()],
148 entrypoint: "test-entrypoint".to_owned(),
149 },
150 );
151 assert_eq!(
152 tester.state,
153 BeginPairingFlow {
154 pairing_url: "https://example.com/pairing-url".to_owned(),
155 scopes: vec!["profile".to_owned()],
156 entrypoint: "test-entrypoint".to_owned(),
157 }
158 );
159 assert_eq!(
160 tester.peek_next_state(CallError),
161 Complete(FxaState::Disconnected)
162 );
163 assert_eq!(
164 tester.peek_next_state(BeginPairingFlowSuccess {
165 oauth_url: "http://example.com/oauth-start".to_owned(),
166 }),
167 Complete(FxaState::Authenticating {
168 oauth_url: "http://example.com/oauth-start".to_owned(),
169 })
170 );
171 }
172}