Buttplug sex toy control library
1// Buttplug Rust Source Code File - See https://buttplug.io for more info.
2//
3// Copyright 2016-2022 Nonpolynomial Labs LLC. All rights reserved.
4//
5// Licensed under the BSD 3-Clause license. See LICENSE file in the project root
6// for full license information.
7
8mod util;
9pub use util::{
10 test_device_manager::{
11 check_test_recv_value,
12 TestDeviceCommunicationManagerBuilder,
13 TestDeviceIdentifier,
14 },
15 test_server_with_device,
16};
17
18use buttplug::{
19 core::{
20 errors::{ButtplugDeviceError, ButtplugError, ButtplugHandshakeError},
21 message::{
22 self,
23 ButtplugMessageSpecVersion,
24 ButtplugServerMessage,
25 Endpoint,
26 BUTTPLUG_CURRENT_MESSAGE_SPEC_VERSION,
27 },
28 },
29 server::{
30 device::hardware::{HardwareCommand, HardwareWriteCmd},
31 ButtplugServer,
32 ButtplugServerBuilder,
33 },
34 util::async_manager,
35};
36use futures::{pin_mut, Stream, StreamExt};
37use std::time::Duration;
38use tokio::time::sleep;
39
40async fn setup_test_server(
41 msg_union: message::ButtplugClientMessage,
42) -> (ButtplugServer, impl Stream<Item = ButtplugServerMessage>) {
43 let server = ButtplugServer::default();
44 let recv = server.event_stream();
45 // assert_eq!(server.server_name, "Test Server");
46 match server
47 .parse_message(msg_union)
48 .await
49 .expect("Test, assuming infallible.")
50 {
51 ButtplugServerMessage::ServerInfo(s) => assert_eq!(
52 s,
53 message::ServerInfo::new("Buttplug Server", ButtplugMessageSpecVersion::Version3, 0)
54 ),
55 _ => panic!("Should've received ok"),
56 }
57 (server, recv)
58}
59
60#[test]
61fn test_server_handshake() {
62 let msg =
63 message::RequestServerInfo::new("Test Client", ButtplugMessageSpecVersion::Version3).into();
64 async_manager::block_on(async {
65 let (server, _recv) = setup_test_server(msg).await;
66 assert!(server.connected());
67 });
68}
69
70#[test]
71fn test_server_handshake_not_done_first() {
72 let msg = message::Ping::default().into();
73 async_manager::block_on(async {
74 let server = ButtplugServer::default();
75 // assert_eq!(server.server_name, "Test Server");
76 let result = server.parse_message(msg).await;
77 assert!(result.is_err());
78 assert!(matches!(
79 result.unwrap_err().original_error(),
80 ButtplugError::ButtplugHandshakeError(ButtplugHandshakeError::RequestServerInfoExpected)
81 ));
82 assert!(!server.connected());
83 });
84}
85
86#[test]
87fn test_client_version_older_than_server() {
88 let msg =
89 message::RequestServerInfo::new("Test Client", ButtplugMessageSpecVersion::Version2).into();
90 async_manager::block_on(async {
91 let server = ButtplugServer::default();
92 // assert_eq!(server.server_name, "Test Server");
93 match server
94 .parse_message(msg)
95 .await
96 .expect("Test, assuming infallible.")
97 {
98 ButtplugServerMessage::ServerInfo(s) => assert_eq!(
99 s,
100 message::ServerInfo::new("Buttplug Server", ButtplugMessageSpecVersion::Version2, 0)
101 ),
102 _ => panic!("Should've received ok"),
103 }
104 });
105}
106
107#[test]
108#[ignore = "Needs to be rewritten to send in via the JSON parser, otherwise we're type bound due to the enum and can't fail"]
109fn test_server_version_older_than_client() {
110 let server = ButtplugServer::default();
111 let msg =
112 message::RequestServerInfo::new("Test Client", ButtplugMessageSpecVersion::Version2).into();
113 async_manager::block_on(async {
114 assert!(
115 server.parse_message(msg).await.is_err(),
116 "Client having higher version than server should fail"
117 );
118 });
119}
120
121#[test]
122fn test_ping_timeout() {
123 async_manager::block_on(async {
124 let server = ButtplugServerBuilder::default()
125 .max_ping_time(100)
126 .finish()
127 .expect("Test, assuming infallible.");
128 let recv = server.event_stream();
129 pin_mut!(recv);
130 let msg = message::RequestServerInfo::new("Test Client", BUTTPLUG_CURRENT_MESSAGE_SPEC_VERSION);
131 sleep(Duration::from_millis(150)).await;
132 let reply = server.parse_message(msg.into()).await;
133 assert!(
134 reply.is_ok(),
135 "ping timer shouldn't start until handshake finished. {:?}",
136 reply
137 );
138 sleep(Duration::from_millis(300)).await;
139 let pingmsg = message::Ping::default();
140 let result = server.parse_message(pingmsg.into()).await;
141 let err = result.unwrap_err();
142 if !matches!(err.original_error(), ButtplugError::ButtplugPingError(_)) {
143 panic!("Got wrong type of error back!");
144 }
145 // Check that we got an event back about the ping out.
146 let msg = recv.next().await.expect("Test, assuming infallible.");
147 if let ButtplugServerMessage::Error(e) = msg {
148 if message::ErrorCode::ErrorPing != e.error_code() {
149 panic!("Didn't get a ping error");
150 }
151 } else {
152 panic!("Didn't get an error message back");
153 }
154 });
155}
156
157#[test]
158fn test_device_stop_on_ping_timeout() {
159 async_manager::block_on(async {
160 let mut builder = TestDeviceCommunicationManagerBuilder::default();
161 let mut device = builder.add_test_device(&TestDeviceIdentifier::new("Massage Demo", None));
162
163 let mut server_builder = ButtplugServerBuilder::default();
164 server_builder.max_ping_time(100);
165 server_builder.comm_manager(builder);
166 let server = server_builder.finish().unwrap();
167
168 let recv = server.event_stream();
169 pin_mut!(recv);
170
171 let msg = message::RequestServerInfo::new("Test Client", BUTTPLUG_CURRENT_MESSAGE_SPEC_VERSION);
172 let mut reply = server.parse_message(msg.into()).await;
173 assert!(reply.is_ok());
174 reply = server
175 .parse_message(message::StartScanning::default().into())
176 .await;
177 assert!(reply.is_ok());
178 // Check that we got an event back about a new device.
179 let mut device_index = 100;
180 while let Some(msg) = recv.next().await {
181 if let ButtplugServerMessage::ScanningFinished(_) = msg {
182 continue;
183 } else if let ButtplugServerMessage::DeviceAdded(da) = msg {
184 assert_eq!(da.device_name(), "Aneros Vivi");
185 device_index = da.device_index();
186 break;
187 } else {
188 panic!(
189 "Returned message was not a DeviceAdded message or timed out: {:?}",
190 msg
191 );
192 }
193 }
194 server
195 .parse_message(
196 message::VibrateCmd::new(device_index, vec![message::VibrateSubcommand::new(0, 0.5)])
197 .into(),
198 )
199 .await
200 .expect("Test, assuming infallible.");
201
202 check_test_recv_value(
203 &mut device,
204 HardwareCommand::Write(HardwareWriteCmd::new(Endpoint::Tx, vec![0xF1, 64], false)),
205 );
206 /*
207 // Wait out the ping, we should get a stop message.
208 let mut i = 0u32;
209 while command_receiver.is_empty() {
210 Delay::new(Duration::from_millis(150)).await;
211 // Breaks out of loop if we wait for too long.
212 i += 1;
213 assert!(i < 10, "Slept for too long while waiting for stop command!");
214 }
215 check_test_recv_value(
216 &command_receiver,
217 HardwareCommand::Write(DeviceWriteCmd::new(Endpoint::Tx, vec![0xF1, 0], false)),
218 );
219 */
220 });
221}
222
223#[test]
224fn test_repeated_handshake() {
225 let msg = message::RequestServerInfo::new("Test Client", ButtplugMessageSpecVersion::Version3);
226 async_manager::block_on(async {
227 let (server, _recv) = setup_test_server((msg.clone()).into()).await;
228 assert!(server.connected());
229 let err = server.parse_message(msg.into()).await.unwrap_err();
230 assert!(matches!(
231 err.original_error(),
232 ButtplugError::ButtplugHandshakeError(ButtplugHandshakeError::HandshakeAlreadyHappened)
233 ));
234 });
235}
236
237#[test]
238fn test_invalid_device_index() {
239 async_manager::block_on(async {
240 let msg = message::RequestServerInfo::new("Test Client", BUTTPLUG_CURRENT_MESSAGE_SPEC_VERSION);
241 let (server, _) = setup_test_server(msg.into()).await;
242 let reply = server
243 .parse_message(message::VibrateCmd::new(10, vec![]).into())
244 .await;
245 assert!(reply.is_err());
246 assert!(matches!(
247 reply.unwrap_err().original_error(),
248 ButtplugError::ButtplugDeviceError(ButtplugDeviceError::DeviceNotAvailable(_))
249 ));
250 });
251}
252
253#[test]
254fn test_device_index_generation() {
255 async_manager::block_on(async {
256 let mut builder = TestDeviceCommunicationManagerBuilder::default();
257 let mut _device1 = builder.add_test_device(&TestDeviceIdentifier::new("Massage Demo", None));
258 let mut _device2 = builder.add_test_device(&TestDeviceIdentifier::new("Massage Demo", None));
259
260 let mut server_builder = ButtplugServerBuilder::default();
261 server_builder.comm_manager(builder);
262 let server = server_builder.finish().unwrap();
263
264 let recv = server.event_stream();
265 pin_mut!(recv);
266 assert!(server
267 .parse_message(
268 message::RequestServerInfo::new("Test Client", BUTTPLUG_CURRENT_MESSAGE_SPEC_VERSION)
269 .into()
270 )
271 .await
272 .is_ok());
273 assert!(server
274 .parse_message(message::StartScanning::default().into())
275 .await
276 .is_ok());
277 // Check that we got an event back about a new device.
278 let mut index = 0u32;
279 while let Some(msg) = recv.next().await {
280 if let ButtplugServerMessage::ScanningFinished(_) = msg {
281 continue;
282 } else if let ButtplugServerMessage::DeviceAdded(da) = msg {
283 assert_eq!(da.device_name(), "Aneros Vivi");
284 // Devices aren't guaranteed to be added in any specific order, the
285 // scheduler will do whatever it wants. So check boundaries instead of
286 // exact.
287 assert!(da.device_index() < 2);
288 index += 1;
289 // Found both devices we're looking for, finish test.
290 if index == 2 {
291 break;
292 }
293 } else {
294 panic!(
295 "Returned message was not a DeviceAdded message or timed out: {:?}",
296 msg
297 );
298 }
299 }
300 });
301}
302
303#[test]
304fn test_server_scanning_finished() {
305 async_manager::block_on(async {
306 let mut builder = TestDeviceCommunicationManagerBuilder::default();
307 let mut _device1 = builder.add_test_device(&TestDeviceIdentifier::new("Massage Demo", None));
308 let mut _device2 = builder.add_test_device(&TestDeviceIdentifier::new("Massage Demo", None));
309
310 let mut server_builder = ButtplugServerBuilder::default();
311 server_builder.comm_manager(builder);
312 let server = server_builder.finish().unwrap();
313
314 let recv = server.event_stream();
315 pin_mut!(recv);
316 assert!(server
317 .parse_message(
318 message::RequestServerInfo::new("Test Client", BUTTPLUG_CURRENT_MESSAGE_SPEC_VERSION)
319 .into()
320 )
321 .await
322 .is_ok());
323 assert!(server
324 .parse_message(message::StartScanning::default().into())
325 .await
326 .is_ok());
327 // Check that we got an event back about a new device.
328 let mut count = 0u32;
329 let mut finish_received = false;
330 // We should get 3 messages: 2 DeviceAdded, 1 ScanningFinished.
331 while let Some(msg) = recv.next().await {
332 if matches!(msg, ButtplugServerMessage::ScanningFinished(_)) {
333 finish_received = true;
334 break;
335 }
336 count += 1;
337 if count == 3 {
338 break;
339 }
340 }
341 assert!(finish_received);
342 });
343}
344
345#[test]
346fn test_server_builder_null_device_config() {
347 async_manager::block_on(async {
348 let mut builder = ButtplugServerBuilder::default();
349 let _ = builder
350 .device_configuration_json(None)
351 .finish()
352 .expect("Test, assuming infallible.");
353 });
354}
355
356#[test]
357fn test_server_builder_device_config_invalid_json() {
358 async_manager::block_on(async {
359 let mut builder = ButtplugServerBuilder::default();
360 assert!(builder
361 .device_configuration_json(Some("{\"Not Valid JSON\"}".to_owned()))
362 .finish()
363 .is_err());
364 });
365}
366
367#[test]
368fn test_server_builder_device_config_schema_break() {
369 async_manager::block_on(async {
370 let mut builder = ButtplugServerBuilder::default();
371 // missing version block.
372 let device_json = r#"{
373 "protocols": {
374 "jejoue": {
375 "btle": {
376 "names": [
377 "Je Joue"
378 ],
379 "services": {
380 "0000fff0-0000-1000-8000-00805f9b34fb": {
381 "tx": "0000fff1-0000-1000-8000-00805f9b34fb"
382 }
383 }
384 },
385 "defaults": {
386 "name": {
387 "en-us": "Je Joue Device"
388 },
389 "messages": {
390 "VibrateCmd": {
391 "FeatureCount": 2,
392 "StepCount": [
393 5,
394 5
395 ]
396 }
397 }
398 }
399 },
400 }
401 }"#;
402 assert!(builder
403 .device_configuration_json(Some(device_json.to_owned()))
404 .finish()
405 .is_err());
406 });
407}
408
409#[test]
410fn test_server_builder_device_config_old_config_version() {
411 async_manager::block_on(async {
412 let mut builder = ButtplugServerBuilder::default();
413 // missing version block.
414 let device_json = r#"{
415 "version": 0,
416 "protocols": {}
417 }
418 "#;
419 assert!(builder
420 .device_configuration_json(Some(device_json.to_owned()))
421 .finish()
422 .is_err());
423 });
424}
425
426#[test]
427fn test_server_builder_null_user_device_config() {
428 async_manager::block_on(async {
429 let mut builder = ButtplugServerBuilder::default();
430 let _ = builder
431 .user_device_configuration_json(None)
432 .finish()
433 .expect("Test, assuming infallible.");
434 });
435}
436
437#[test]
438fn test_server_builder_user_device_config_invalid_json() {
439 async_manager::block_on(async {
440 let mut builder = ButtplugServerBuilder::default();
441 assert!(builder
442 .user_device_configuration_json(Some("{\"Not Valid JSON\"}".to_owned()))
443 .finish()
444 .is_err());
445 });
446}
447
448#[test]
449fn test_server_builder_user_device_config_schema_break() {
450 async_manager::block_on(async {
451 let mut builder = ButtplugServerBuilder::default();
452 // missing version block.
453 let device_json = r#"{
454 "protocols": {
455 "jejoue": {
456 "btle": {
457 "names": [
458 "Je Joue"
459 ],
460 "services": {
461 "0000fff0-0000-1000-8000-00805f9b34fb": {
462 "tx": "0000fff1-0000-1000-8000-00805f9b34fb"
463 }
464 }
465 },
466 "defaults": {
467 "name": {
468 "en-us": "Je Joue Device"
469 },
470 "messages": {
471 "VibrateCmd": {
472 "FeatureCount": 2,
473 "StepCount": [
474 5,
475 5
476 ]
477 }
478 }
479 }
480 },
481 }
482 }"#;
483 assert!(builder
484 .user_device_configuration_json(Some(device_json.to_owned()))
485 .finish()
486 .is_err());
487 });
488}
489
490#[test]
491#[ignore = "Skip until we've figured out whether we actually want version differences to fail."]
492fn test_server_builder_user_device_config_old_config_version() {
493 async_manager::block_on(async {
494 let mut builder = ButtplugServerBuilder::default();
495 // missing version block.
496 let device_json = r#"{
497 "version": 0,
498 "protocols": {}
499 }
500 "#;
501 assert!(builder
502 .user_device_configuration_json(Some(device_json.to_owned()))
503 .finish()
504 .is_err());
505 });
506}
507
508// TODO Test sending system message (Id 0)
509// TODO Test sending system message (Ok but Id > 0)
510// TODO Test scan with no comm managers
511// TODO Test message with no RequestServerInfo first
512// TODO Test sending device command for device that doesn't exist (in server)