implement some tests
This commit is contained in:
		
							parent
							
								
									e4df2e5075
								
							
						
					
					
						commit
						997478801c
					
				
					 11 changed files with 483 additions and 8 deletions
				
			
		
							
								
								
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							|  | @ -1800,7 +1800,6 @@ dependencies = [ | |||
|  "nzr-api", | ||||
|  "serde_json", | ||||
|  "tabled", | ||||
|  "tarpc", | ||||
|  "tokio", | ||||
|  "tokio-serde 0.9.0", | ||||
| ] | ||||
|  | @ -1811,6 +1810,7 @@ version = "0.1.0" | |||
| dependencies = [ | ||||
|  "diesel", | ||||
|  "figment", | ||||
|  "futures", | ||||
|  "hickory-proto", | ||||
|  "log", | ||||
|  "serde", | ||||
|  |  | |||
|  | @ -9,12 +9,6 @@ clap = { version = "4.0.26", features = ["derive"] } | |||
| home = "0.5.4" | ||||
| tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } | ||||
| tokio-serde = { version = "0.9", features = ["bincode"] } | ||||
| tarpc = { version = "0.34", features = [ | ||||
|     "tokio1", | ||||
|     "unix", | ||||
|     "serde-transport", | ||||
|     "serde-transport-bincode", | ||||
| ] } | ||||
| tabled = "0.15" | ||||
| serde_json = "1" | ||||
| log = "0.4.17" | ||||
|  |  | |||
|  | @ -6,13 +6,23 @@ edition = "2021" | |||
| [dependencies] | ||||
| figment = { version = "0.10.8", features = ["json", "toml", "env"] } | ||||
| serde = { version = "1", features = ["derive"] } | ||||
| tarpc = { version = "0.34", features = ["tokio1", "unix"] } | ||||
| tarpc = { version = "0.34", features = [ | ||||
|     "tokio1", | ||||
|     "unix", | ||||
|     "serde-transport", | ||||
|     "serde-transport-bincode", | ||||
| ] } | ||||
| tokio = { version = "1.0", features = ["macros"] } | ||||
| uuid = { version = "1.2.2", features = ["serde"] } | ||||
| hickory-proto = { version = "0.24", features = ["serde-config"] } | ||||
| log = "0.4.17" | ||||
| sqlx = "0.8" | ||||
| diesel = { version = "2.2", optional = true } | ||||
| futures = { version = "0.3", optional = true } | ||||
| 
 | ||||
| [dev-dependencies] | ||||
| uuid = { version = "1.2.2", features = ["serde", "v4"] } | ||||
| 
 | ||||
| [features] | ||||
| diesel = ["dep:diesel"] | ||||
| mock = ["dep:futures"] | ||||
|  |  | |||
|  | @ -4,6 +4,8 @@ use model::{CreateStatus, Instance, Subnet}; | |||
| 
 | ||||
| pub mod args; | ||||
| pub mod config; | ||||
| #[cfg(feature = "mock")] | ||||
| pub mod mock; | ||||
| pub mod model; | ||||
| pub mod net; | ||||
| 
 | ||||
|  | @ -63,4 +65,5 @@ pub fn new_client(sock: tokio::net::UnixStream) -> NazrinClient { | |||
|     NazrinClient::new(Default::default(), transport).spawn() | ||||
| } | ||||
| 
 | ||||
| pub use tarpc::client::RpcError; | ||||
| pub use tarpc::context::current as default_ctx; | ||||
|  |  | |||
							
								
								
									
										70
									
								
								nzr-api/src/mock/client.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								nzr-api/src/mock/client.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,70 @@ | |||
| use std::net::Ipv4Addr; | ||||
| 
 | ||||
| use crate::{args, model, net::cidr::CidrV4}; | ||||
| 
 | ||||
| pub trait NzrClientExt { | ||||
|     #[allow(async_fn_in_trait)] | ||||
|     async fn new_mock_instance( | ||||
|         &mut self, | ||||
|         name: impl AsRef<str>, | ||||
|     ) -> Result<Result<model::Instance, String>, crate::RpcError>; | ||||
| } | ||||
| 
 | ||||
| impl NzrClientExt for crate::NazrinClient { | ||||
|     async fn new_mock_instance( | ||||
|         &mut self, | ||||
|         name: impl AsRef<str>, | ||||
|     ) -> Result<Result<model::Instance, String>, crate::RpcError> { | ||||
|         let name = name.as_ref().to_owned(); | ||||
| 
 | ||||
|         let subnet = self | ||||
|             .new_subnet( | ||||
|                 crate::default_ctx(), | ||||
|                 model::Subnet { | ||||
|                     name: "mock".to_owned(), | ||||
|                     data: model::SubnetData { | ||||
|                         ifname: "eth0".to_string(), | ||||
|                         network: CidrV4::new(Ipv4Addr::new(192, 0, 2, 0), 24), | ||||
|                         start_host: Ipv4Addr::new(192, 0, 2, 10), | ||||
|                         end_host: Ipv4Addr::new(192, 0, 2, 254), | ||||
|                         gateway4: Some(Ipv4Addr::new(192, 0, 2, 1)), | ||||
|                         dns: vec![Ipv4Addr::new(192, 0, 2, 5)], | ||||
|                         domain_name: None, | ||||
|                         vlan_id: None, | ||||
|                     }, | ||||
|                 }, | ||||
|             ) | ||||
|             .await | ||||
|             .unwrap() | ||||
|             .ok(); | ||||
| 
 | ||||
|         let uuid = self | ||||
|             .new_instance( | ||||
|                 crate::default_ctx(), | ||||
|                 args::NewInstance { | ||||
|                     name: name.clone(), | ||||
|                     title: None, | ||||
|                     description: None, | ||||
|                     subnet: subnet.map_or_else(|| "mock".to_owned(), |m| m.name), | ||||
|                     base_image: "linux2".to_owned(), | ||||
|                     cores: 2, | ||||
|                     memory: 1024, | ||||
|                     disk_sizes: (10, None), | ||||
|                     ci_userdata: None, | ||||
|                 }, | ||||
|             ) | ||||
|             .await? | ||||
|             .unwrap(); | ||||
|         // poll to "complete"
 | ||||
|         self.poll_new_instance(crate::default_ctx(), uuid) | ||||
|             .await? | ||||
|             .unwrap(); | ||||
| 
 | ||||
|         let inst = self | ||||
|             .poll_new_instance(crate::default_ctx(), uuid) | ||||
|             .await? | ||||
|             .and_then(|cs| cs.result) | ||||
|             .unwrap(); | ||||
|         Ok(inst) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										274
									
								
								nzr-api/src/mock/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										274
									
								
								nzr-api/src/mock/mod.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,274 @@ | |||
| pub mod client; | ||||
| #[cfg(test)] | ||||
| mod test; | ||||
| 
 | ||||
| use std::{collections::HashMap, sync::Arc}; | ||||
| 
 | ||||
| use tarpc::server::{BaseChannel, Channel as _}; | ||||
| 
 | ||||
| use futures::{future, StreamExt}; | ||||
| use tokio::{sync::RwLock, task::JoinHandle}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     model, | ||||
|     net::{cidr::CidrV4, mac::MacAddr}, | ||||
|     InstanceQuery, Nazrin, NazrinClient, | ||||
| }; | ||||
| 
 | ||||
| pub struct MockServerHandle<T>(JoinHandle<T>); | ||||
| 
 | ||||
| impl<T> Drop for MockServerHandle<T> { | ||||
|     fn drop(&mut self) { | ||||
|         self.0.abort(); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl<T> From<JoinHandle<T>> for MockServerHandle<T> { | ||||
|     fn from(value: JoinHandle<T>) -> Self { | ||||
|         Self(value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| #[derive(Default)] | ||||
| struct MockDb { | ||||
|     instances: Vec<Option<model::Instance>>, | ||||
|     subnets: Vec<Option<model::Subnet>>, | ||||
|     subnet_lease: HashMap<i32, u32>, | ||||
|     ci_userdatas: HashMap<String, Vec<u8>>, | ||||
|     create_tasks: HashMap<uuid::Uuid, (model::Instance, bool)>, | ||||
| } | ||||
| 
 | ||||
| /// Mock Nazrin RPC server for testing, where the full server isn't required.
 | ||||
| ///
 | ||||
| /// Note that this intentionally does not perform SQL model testing!
 | ||||
| #[derive(Clone, Default)] | ||||
| pub struct MockServer { | ||||
|     db: Arc<RwLock<MockDb>>, | ||||
| } | ||||
| 
 | ||||
| impl MockServer { | ||||
|     /// Marks a create_task as complete, assuming it exists
 | ||||
|     pub async fn complete_task(&mut self, task_id: uuid::Uuid) { | ||||
|         let mut db = self.db.write().await; | ||||
|         if let Some((_inst, done)) = db.create_tasks.get_mut(&task_id) { | ||||
|             let _ = std::mem::replace(done, true); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Nazrin for MockServer { | ||||
|     async fn new_instance( | ||||
|         self, | ||||
|         _: tarpc::context::Context, | ||||
|         build_args: crate::args::NewInstance, | ||||
|     ) -> Result<uuid::Uuid, String> { | ||||
|         let mut db = self.db.write().await; | ||||
|         let Some(net_pos) = db | ||||
|             .subnets | ||||
|             .iter() | ||||
|             .position(|s| s.as_ref().filter(|s| s.name == build_args.subnet).is_some()) | ||||
|         else { | ||||
|             return Err("Subnet doesn't exist".to_owned()); | ||||
|         }; | ||||
|         let subnet = db.subnets[net_pos].as_ref().unwrap().clone(); | ||||
|         let cur_lease = *(db | ||||
|             .subnet_lease | ||||
|             .get(&(net_pos as i32)) | ||||
|             .unwrap_or(&(subnet.data.start_bytes() as u32))); | ||||
|         let instance = model::Instance { | ||||
|             name: build_args.name.clone(), | ||||
|             id: -1, | ||||
|             lease: model::Lease { | ||||
|                 subnet: build_args.subnet, | ||||
|                 addr: CidrV4::new( | ||||
|                     subnet | ||||
|                         .data | ||||
|                         .network | ||||
|                         .make_ip(cur_lease) | ||||
|                         .map_err(|e| e.to_string())?, | ||||
|                     subnet.data.network.cidr(), | ||||
|                 ), | ||||
|                 mac_addr: MacAddr::new(0x02, 0x04, 0x08, 0x0a, 0x0c, 0x0f), | ||||
|             }, | ||||
|             state: model::DomainState::NoState, | ||||
|         }; | ||||
|         db.ci_userdatas | ||||
|             .insert(build_args.name, build_args.ci_userdata.unwrap_or_default()); | ||||
|         let id = uuid::Uuid::new_v4(); | ||||
|         db.create_tasks.insert(id, (instance, false)); | ||||
| 
 | ||||
|         Ok(id) | ||||
|     } | ||||
| 
 | ||||
|     async fn poll_new_instance( | ||||
|         mut self, | ||||
|         _: tarpc::context::Context, | ||||
|         task_id: uuid::Uuid, | ||||
|     ) -> Option<crate::model::CreateStatus> { | ||||
|         let db = self.db.read().await; | ||||
|         let (inst, done) = db.create_tasks.get(&task_id)?; | ||||
|         let done = *done; | ||||
| 
 | ||||
|         if done { | ||||
|             Some(model::CreateStatus { | ||||
|                 status_text: "Done!".to_owned(), | ||||
|                 completion: 1.0, | ||||
|                 result: Some(Ok(inst.clone())), | ||||
|             }) | ||||
|         } else { | ||||
|             let mut inst = inst.clone(); | ||||
|             // Drop the read-only DB to get a write lock
 | ||||
|             std::mem::drop(db); | ||||
|             let mut db = self.db.write().await; | ||||
|             inst.id = (db.instances.len() + 1) as i32; | ||||
|             db.instances.push(Some(inst.clone())); | ||||
|             // Drop the writeable DB to avoid deadlock
 | ||||
|             std::mem::drop(db); | ||||
|             self.complete_task(task_id).await; | ||||
|             Some(model::CreateStatus { | ||||
|                 status_text: "Working on it...".to_owned(), | ||||
|                 completion: 0.50, | ||||
|                 result: None, | ||||
|             }) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     async fn delete_instance(self, _: tarpc::context::Context, name: String) -> Result<(), String> { | ||||
|         let mut db = self.db.write().await; | ||||
|         let Some(inst) = db | ||||
|             .instances | ||||
|             .iter_mut() | ||||
|             .find(|i| i.as_ref().filter(|i| i.name == name).is_some()) | ||||
|             .take() | ||||
|         else { | ||||
|             return Err("Instance doesn't exist".to_owned()); | ||||
|         }; | ||||
|         inst.take(); | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     async fn find_instance( | ||||
|         self, | ||||
|         _: tarpc::context::Context, | ||||
|         query: crate::InstanceQuery, | ||||
|     ) -> Result<Option<crate::model::Instance>, String> { | ||||
|         let db = self.db.read().await; | ||||
| 
 | ||||
|         let res = { | ||||
|             db.instances | ||||
|                 .iter() | ||||
|                 .find(|opt| { | ||||
|                     opt.as_ref() | ||||
|                         .map(|inst| match &query { | ||||
|                             InstanceQuery::Ipv4Addr(addr) => &inst.lease.addr.addr == addr, | ||||
|                             InstanceQuery::MacAddr(addr) => &inst.lease.mac_addr == addr, | ||||
|                             InstanceQuery::Name(name) => &inst.name == name, | ||||
|                         }) | ||||
|                         .is_some() | ||||
|                 }) | ||||
|                 .and_then(|opt| opt.as_ref().cloned()) | ||||
|         }; | ||||
| 
 | ||||
|         Ok(res) | ||||
|     } | ||||
| 
 | ||||
|     async fn get_instance_userdata( | ||||
|         self, | ||||
|         _: tarpc::context::Context, | ||||
|         id: i32, | ||||
|     ) -> Result<Vec<u8>, String> { | ||||
|         let db = self.db.read().await; | ||||
|         let Some(inst) = db.instances.get(id as usize).and_then(|o| o.as_ref()) else { | ||||
|             return Err("No such instance".to_owned()); | ||||
|         }; | ||||
|         Ok(db.ci_userdatas.get(&inst.name).cloned().unwrap_or_default()) | ||||
|     } | ||||
| 
 | ||||
|     async fn get_instances( | ||||
|         self, | ||||
|         _: tarpc::context::Context, | ||||
|         _with_status: bool, | ||||
|     ) -> Result<Vec<crate::model::Instance>, String> { | ||||
|         let db = self.db.read().await; | ||||
|         Ok(db | ||||
|             .instances | ||||
|             .iter() | ||||
|             .filter_map(|inst| inst.clone()) | ||||
|             .collect()) | ||||
|     } | ||||
| 
 | ||||
|     async fn new_subnet( | ||||
|         self, | ||||
|         _: tarpc::context::Context, | ||||
|         build_args: crate::model::Subnet, | ||||
|     ) -> Result<crate::model::Subnet, String> { | ||||
|         let mut db = self.db.write().await; | ||||
|         let subnet = build_args.clone(); | ||||
|         db.subnets.push(Some(build_args)); | ||||
|         Ok(subnet) | ||||
|     } | ||||
| 
 | ||||
|     async fn modify_subnet( | ||||
|         self, | ||||
|         _: tarpc::context::Context, | ||||
|         _edit_args: crate::model::Subnet, | ||||
|     ) -> Result<crate::model::Subnet, String> { | ||||
|         todo!() | ||||
|     } | ||||
| 
 | ||||
|     async fn get_subnets( | ||||
|         self, | ||||
|         _: tarpc::context::Context, | ||||
|     ) -> Result<Vec<crate::model::Subnet>, String> { | ||||
|         let db = self.db.read().await; | ||||
|         Ok(db.subnets.iter().filter_map(|net| net.clone()).collect()) | ||||
|     } | ||||
| 
 | ||||
|     async fn delete_subnet( | ||||
|         self, | ||||
|         _: tarpc::context::Context, | ||||
|         interface: String, | ||||
|     ) -> Result<(), String> { | ||||
|         let mut db = self.db.write().await; | ||||
|         db.instances | ||||
|             .iter() | ||||
|             .filter_map(|inst| inst.as_ref()) | ||||
|             .for_each(|inst| { | ||||
|                 if inst.lease.subnet == interface { | ||||
|                     todo!("what now") | ||||
|                 } | ||||
|             }); | ||||
|         let Some(subnet) = db | ||||
|             .subnets | ||||
|             .iter_mut() | ||||
|             .find(|net| net.as_ref().filter(|n| n.name == interface).is_some()) | ||||
|         else { | ||||
|             return Err("Subnet doesn't exist".to_owned()); | ||||
|         }; | ||||
|         subnet.take(); | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     async fn garbage_collect(self, _: tarpc::context::Context) -> Result<(), String> { | ||||
|         todo!() | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /// Generates a MockServer task and connected client.
 | ||||
| pub async fn spawn_c2s() -> (NazrinClient, MockServerHandle<()>) { | ||||
|     let (client_transport, server_transport) = tarpc::transport::channel::unbounded(); | ||||
|     let server: MockServerHandle<()> = { | ||||
|         tokio::spawn(async move { | ||||
|             BaseChannel::with_defaults(server_transport) | ||||
|                 .execute(MockServer::default().serve()) | ||||
|                 .for_each(|rpc| { | ||||
|                     tokio::spawn(rpc); | ||||
|                     future::ready(()) | ||||
|                 }) | ||||
|                 .await; | ||||
|         }) | ||||
|         .into() | ||||
|     }; | ||||
|     let client = NazrinClient::new(Default::default(), client_transport).spawn(); | ||||
|     (client, server) | ||||
| } | ||||
							
								
								
									
										68
									
								
								nzr-api/src/mock/test.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								nzr-api/src/mock/test.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,68 @@ | |||
| use crate::{args, model}; | ||||
| 
 | ||||
| #[tokio::test] | ||||
| async fn test_the_tester() { | ||||
|     let (client, _server) = super::spawn_c2s().await; | ||||
|     client | ||||
|         .new_subnet( | ||||
|             crate::default_ctx(), | ||||
|             model::Subnet { | ||||
|                 name: "test".to_owned(), | ||||
|                 data: model::SubnetData { | ||||
|                     ifname: "eth0".into(), | ||||
|                     network: "192.0.2.0/24".parse().unwrap(), | ||||
|                     start_host: "192.0.2.10".parse().unwrap(), | ||||
|                     end_host: "192.0.2.254".parse().unwrap(), | ||||
|                     gateway4: Some("192.0.2.1".parse().unwrap()), | ||||
|                     dns: Vec::new(), | ||||
|                     domain_name: None, | ||||
|                     vlan_id: None, | ||||
|                 }, | ||||
|             }, | ||||
|         ) | ||||
|         .await | ||||
|         .expect("RPC error") | ||||
|         .expect("create subnet failed"); | ||||
|     let task_id = client | ||||
|         .new_instance( | ||||
|             crate::default_ctx(), | ||||
|             args::NewInstance { | ||||
|                 name: "my-inst".to_owned(), | ||||
|                 title: None, | ||||
|                 description: None, | ||||
|                 subnet: "test".to_owned(), | ||||
|                 base_image: "some-kinda-linux".to_owned(), | ||||
|                 cores: 42, | ||||
|                 memory: 1337, | ||||
|                 disk_sizes: (10, None), | ||||
|                 ci_userdata: None, | ||||
|             }, | ||||
|         ) | ||||
|         .await | ||||
|         .expect("RPC error") | ||||
|         .expect("create instance failed"); | ||||
|     // Poll the instance creation to "complete" it
 | ||||
|     let poll_inst = client | ||||
|         .poll_new_instance(crate::default_ctx(), task_id) | ||||
|         .await | ||||
|         .unwrap() | ||||
|         .unwrap(); | ||||
|     assert!(poll_inst.result.is_none()); | ||||
|     assert!(poll_inst.completion < 1.0); | ||||
|     let poll_inst = client | ||||
|         .poll_new_instance(crate::default_ctx(), task_id) | ||||
|         .await | ||||
|         .unwrap() | ||||
|         .unwrap(); | ||||
|     assert!(poll_inst.result.is_some()); | ||||
|     assert_eq!(poll_inst.completion, 1.0); | ||||
|     let instances = client | ||||
|         .get_instances(crate::default_ctx(), false) | ||||
|         .await | ||||
|         .expect("RPC error") | ||||
|         .expect("get instances failed"); | ||||
| 
 | ||||
|     assert_eq!(instances.len(), 1); | ||||
|     assert_eq!(&instances[0].name, "my-inst"); | ||||
|     assert_eq!(&instances[0].lease.subnet, "test"); | ||||
| } | ||||
|  | @ -12,3 +12,6 @@ tracing-subscriber = "0.3" | |||
| anyhow = "1" | ||||
| askama = "0.12" | ||||
| moka = { version = "0.12.8", features = ["future"] } | ||||
| 
 | ||||
| [dev-dependencies] | ||||
| nzr-api = { path = "../nzr-api", features = ["mock"] } | ||||
|  |  | |||
|  | @ -46,6 +46,15 @@ impl Context { | |||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     #[cfg(test)] | ||||
|     pub fn new_mock(cfg: Config, api_client: NazrinClient) -> Self { | ||||
|         Self { | ||||
|             api_client, | ||||
|             config: Arc::new(cfg), | ||||
|             host_cache: Cache::new(5), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Internal function to hydrate the instance metadata, if needed
 | ||||
|     async fn get_instmeta(&self, addr: Ipv4Addr) -> Result<Option<InstanceMeta>> { | ||||
|         if let Some(meta) = self.host_cache.get(&addr).await { | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| mod ctx; | ||||
| mod model; | ||||
| #[cfg(test)] | ||||
| mod test; | ||||
| 
 | ||||
| use std::{ | ||||
|     net::{IpAddr, SocketAddr}, | ||||
|  |  | |||
							
								
								
									
										42
									
								
								omyacid/src/test.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								omyacid/src/test.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | |||
| use std::net::SocketAddr; | ||||
| 
 | ||||
| use axum::extract::{ConnectInfo, State}; | ||||
| use nzr_api::{ | ||||
|     config::{CloudConfig, Config}, | ||||
|     mock::{self, client::NzrClientExt}, | ||||
| }; | ||||
| 
 | ||||
| use crate::ctx; | ||||
| 
 | ||||
| #[tokio::test] | ||||
| async fn get_metadata() { | ||||
|     let (mut client, _server) = mock::spawn_c2s().await; | ||||
| 
 | ||||
|     let inst = client | ||||
|         .new_mock_instance("something") | ||||
|         .await | ||||
|         .unwrap() | ||||
|         .unwrap(); | ||||
| 
 | ||||
|     let cfg = Config { | ||||
|         cloud: CloudConfig { | ||||
|             listen_addr: "0.0.0.0".into(), | ||||
|             port: 80, | ||||
|             admin_user: "admin".to_owned(), | ||||
|         }, | ||||
|         ..Default::default() | ||||
|     }; | ||||
|     let ctx = ctx::Context::new_mock(cfg, client); | ||||
|     let inst_sock: SocketAddr = (inst.lease.addr.addr, 54545).into(); | ||||
| 
 | ||||
|     let metadata = crate::get_meta_data(State(ctx.clone()), ConnectInfo(inst_sock)) | ||||
|         .await | ||||
|         .unwrap(); | ||||
| 
 | ||||
|     assert_eq!( | ||||
|         metadata, | ||||
|         "instance_id: \"iid-something\"\nlocal_hostname: \"something\"\ndefault_username: \"admin\"" | ||||
|     ) | ||||
| 
 | ||||
|     // TODO: Instance with SSH keys
 | ||||
| } | ||||
		Loading…
	
		Reference in a new issue