Buttplug sex toy control library
at buttplug-6.2.1 512 lines 15 kB view raw
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)