1use crate::config::directories::{
2 get_shared_network_data_directory, get_shared_wallet_config_path,
3};
4use crate::config::model::dfinity::{
5 Config, ConfigDefaults, ConfigLocalProvider, ConfigNetwork, DEFAULT_PROJECT_LOCAL_BIND,
6 DEFAULT_SHARED_LOCAL_BIND, NetworkType, NetworksConfig,
7};
8use crate::config::model::local_server_descriptor::{
9 LocalNetworkScopeDescriptor, LocalServerDescriptor,
10};
11use crate::config::model::network_descriptor::{
12 NetworkDescriptor, NetworkTypeDescriptor, PLAYGROUND_NETWORK_NAME,
13};
14use crate::error::network_config::NetworkConfigError::{
15 self, DetermineSharedNetworkDirectoryFailed, NetworkNotFound, NoNetworkContext,
16 NoProvidersForNetwork, ParsePortValueFailed, ParseProviderUrlFailed, ReadWebserverPortFailed,
17};
18use crate::identity::WALLET_CONFIG_FILENAME;
19use crate::util;
20use lazy_static::lazy_static;
21use serde_json::json;
22use slog::{Logger, debug, info, warn};
23use std::path::{Display, Path, PathBuf};
24use std::sync::{Arc, RwLock};
25use url::Url;
26
27lazy_static! {
28 static ref NETWORK_CONTEXT: Arc<RwLock<Option<String>>> = Arc::new(RwLock::new(None));
29}
30
31fn set_network_context(network: Option<String>) {
32 let name = network.unwrap_or_else(|| "local".to_string());
33
34 let mut n = NETWORK_CONTEXT.write().unwrap();
35 *n = Some(name);
36}
37
38pub fn get_network_context() -> Result<String, NetworkConfigError> {
39 NETWORK_CONTEXT
40 .read()
41 .unwrap()
42 .clone()
43 .ok_or(NoNetworkContext())
44}
45
46pub enum LocalBindDetermination {
47 AsConfigured,
49
50 ApplyRunningWebserverPort,
52}
53
54fn config_network_to_network_descriptor(
55 network_name: &str,
56 config_network: &ConfigNetwork,
57 project_defaults: Option<&ConfigDefaults>,
58 data_directory: PathBuf,
59 local_scope: LocalNetworkScopeDescriptor,
60 ephemeral_wallet_config_path: Option<PathBuf>,
61 local_bind_determination: &LocalBindDetermination,
62 default_local_bind: &str,
63 legacy_pid_path: Option<PathBuf>,
64) -> Result<NetworkDescriptor, NetworkConfigError> {
65 match config_network {
66 ConfigNetwork::ConfigNetworkProvider(network_provider) => {
67 let providers = if !network_provider.providers.is_empty() {
68 network_provider
69 .providers
70 .iter()
71 .map(|provider| parse_provider_url(provider))
72 .collect::<Result<_, NetworkConfigError>>()
73 } else {
74 Err(NoProvidersForNetwork(network_name.to_string()))
75 }?;
76 let playground = network_provider.playground.clone();
77 let is_ic = NetworkDescriptor::is_ic(network_name, &providers);
78 Ok(NetworkDescriptor {
79 name: network_name.to_string(),
80 providers,
81 r#type: NetworkTypeDescriptor::new(
82 network_provider.r#type,
83 ephemeral_wallet_config_path,
84 playground,
85 )?,
86 is_ic,
87 is_ad_hoc: false,
88 local_server_descriptor: None,
89 })
90 }
91 ConfigNetwork::ConfigLocalProvider(local_provider) => {
92 let bitcoin = local_provider
93 .bitcoin
94 .clone()
95 .or_else(|| project_defaults.and_then(|x| x.bitcoin.clone()))
96 .unwrap_or_default();
97 let dogecoin = local_provider
98 .dogecoin
99 .clone()
100 .or_else(|| project_defaults.and_then(|x| x.dogecoin.clone()))
101 .unwrap_or_default();
102 let canister_http = local_provider
103 .canister_http
104 .clone()
105 .or_else(|| project_defaults.and_then(|x| x.canister_http.clone()))
106 .unwrap_or_default();
107 let proxy = local_provider
108 .proxy
109 .clone()
110 .or_else(|| project_defaults.and_then(|x| x.proxy.clone()))
111 .unwrap_or_default();
112 let replica = local_provider
113 .replica
114 .clone()
115 .or_else(|| project_defaults.and_then(|x| x.replica.clone()))
116 .unwrap_or_default();
117 let playground = local_provider.playground.clone();
118
119 let network_type = NetworkTypeDescriptor::new(
120 local_provider.r#type,
121 ephemeral_wallet_config_path,
122 playground,
123 )?;
124 let bind_address = get_local_bind_address(
125 local_provider,
126 local_bind_determination,
127 &data_directory,
128 default_local_bind,
129 )?;
130 let provider_url = format!("http://{bind_address}");
131 let providers = vec![parse_provider_url(&provider_url)?];
132 let local_server_descriptor = LocalServerDescriptor::new(
133 data_directory,
134 bind_address,
135 bitcoin,
136 dogecoin,
137 canister_http,
138 proxy,
139 replica,
140 local_scope,
141 legacy_pid_path,
142 )?;
143 Ok(NetworkDescriptor {
144 name: network_name.to_string(),
145 providers,
146 r#type: network_type,
147 is_ic: false,
148 is_ad_hoc: false,
149 local_server_descriptor: Some(local_server_descriptor),
150 })
151 }
152 }
153}
154
155pub fn create_network_descriptor(
156 project_config: Option<Arc<Config>>,
157 shared_config: Arc<NetworksConfig>,
158 network: Option<String>,
159 logger: Option<Logger>,
160 local_bind_determination: LocalBindDetermination,
161) -> Result<NetworkDescriptor, NetworkConfigError> {
162 let logger = (logger.clone()).unwrap_or_else(|| Logger::root(slog::Discard, slog::o!()));
163
164 set_network_context(network);
165 let network_name = get_network_context()?;
166
167 create_mainnet_network_descriptor(&network_name, &logger)
168 .or_else(|| {
169 create_project_network_descriptor(
170 &network_name,
171 project_config.clone(),
172 &local_bind_determination,
173 &logger,
174 )
175 })
176 .or_else(|| {
177 let project_config_for_warnings_only = project_config;
178 create_shared_network_descriptor(
179 &network_name,
180 shared_config,
181 project_config_for_warnings_only,
182 &local_bind_determination,
183 &logger,
184 )
185 })
186 .or_else(|| create_default_network_from_name(&network_name, &logger).map(Ok))
187 .or_else(|| create_url_based_network_descriptor(&network_name))
188 .unwrap_or(Err(NetworkNotFound(network_name)))
189}
190
191fn create_mainnet_network_descriptor(
192 network_name: &str,
193 logger: &Logger,
194) -> Option<Result<NetworkDescriptor, NetworkConfigError>> {
195 if network_name == "ic" {
196 info!(
197 logger,
198 "Using built-in definition for network 'ic' (mainnet)"
199 );
200 Some(Ok(NetworkDescriptor::ic()))
201 } else {
202 None
203 }
204}
205
206fn create_url_based_network_descriptor(
207 network_name: &str,
208) -> Option<Result<NetworkDescriptor, NetworkConfigError>> {
209 parse_provider_url(network_name).ok().map(|url| {
210 let name = util::network_to_pathcompat(network_name);
213 let is_ic = NetworkDescriptor::is_ic(&name, &vec![url.to_string()]);
214 let data_directory = get_shared_network_data_directory(network_name)
215 .map_err(DetermineSharedNetworkDirectoryFailed)?;
216 let network_type = NetworkTypeDescriptor::new(
217 NetworkType::Ephemeral,
218 Some(data_directory.join(WALLET_CONFIG_FILENAME)),
219 None,
220 )?;
221 Ok(NetworkDescriptor {
222 name,
223 providers: vec![url],
224 r#type: network_type,
225 is_ic,
226 is_ad_hoc: true,
227 local_server_descriptor: None,
228 })
229 })
230}
231
232fn create_shared_network_descriptor(
233 network_name: &str,
234 shared_config: Arc<NetworksConfig>,
235 project_config_for_warnings_only: Option<Arc<Config>>,
236 local_bind_determination: &LocalBindDetermination,
237 logger: &Logger,
238) -> Option<Result<NetworkDescriptor, NetworkConfigError>> {
239 let shared_config_file_exists = shared_config.get_path().is_file();
240 let shared_config_display_path = shared_config.get_path().display();
241 let network = shared_config.get_interface().get_network(network_name);
242 let network = match (network_name, network) {
243 ("local", None) => {
244 info!(
245 logger,
246 "Using the default configuration for the local shared network."
247 );
248
249 Some(ConfigNetwork::ConfigLocalProvider(ConfigLocalProvider {
250 bind: Some(String::from(DEFAULT_SHARED_LOCAL_BIND)),
251 r#type: NetworkType::Ephemeral,
252 bitcoin: None,
253 dogecoin: None,
254 bootstrap: None,
255 canister_http: None,
256 replica: None,
257 playground: None,
258 proxy: None,
259 }))
260 }
261 (network_name, None) => {
262 if shared_config_file_exists {
263 debug!(
264 logger,
265 "There is no shared network '{}' defined in {}",
266 &shared_config_display_path,
267 network_name
268 );
269 } else {
270 debug!(
271 logger,
272 "There is no shared network '{}' because {} does not exist.",
273 network_name,
274 &shared_config_display_path
275 );
276 }
277 None
278 }
279 (network_name, Some(network)) => {
280 info!(
281 logger,
282 "Using shared network '{}' defined in {}",
283 network_name,
284 shared_config.get_path().display()
285 );
286 Some(network.clone())
287 }
288 };
289
290 network.as_ref().map(|config_network| {
291 warn_if_ignoring_project_defaults_in_shared_network(
292 network_name,
293 &shared_config_display_path,
294 project_config_for_warnings_only,
295 logger,
296 );
297
298 let data_directory = get_shared_network_data_directory(network_name)?;
299
300 let ephemeral_wallet_config_path = get_shared_wallet_config_path(network_name)?;
301
302 let local_scope = LocalNetworkScopeDescriptor::shared(&data_directory);
303 config_network_to_network_descriptor(
304 network_name,
305 config_network,
306 None,
307 data_directory,
308 local_scope,
309 ephemeral_wallet_config_path,
310 local_bind_determination,
311 DEFAULT_SHARED_LOCAL_BIND,
312 None,
313 )
314 })
315}
316
317fn warn_if_ignoring_project_defaults_in_shared_network(
318 network_name: &str,
319 shared_config_display_path: &Display,
320 project_config_for_warnings_only: Option<Arc<Config>>,
321 logger: &Logger,
322) {
323 if let Some(project_config_for_warnings_only) = project_config_for_warnings_only {
324 let defaults = project_config_for_warnings_only.get_json().get("defaults");
325 let bitcoin = defaults.and_then(|x| x.get("bitcoin")).cloned();
326 let replica = defaults.and_then(|x| x.get("replica")).cloned();
327 let canister_http = defaults.and_then(|x| x.get("canister_http")).cloned();
328
329 if bitcoin.is_some() || replica.is_some() || canister_http.is_some() {
330 let mut example_network_json = json!({});
331 if let Some(bitcoin) = bitcoin {
332 example_network_json["bitcoin"] = bitcoin;
333 }
334 if let Some(replica) = replica {
335 example_network_json["replica"] = replica;
336 }
337 if let Some(canister_http) = canister_http {
338 example_network_json["canister_http"] = canister_http;
339 }
340 let example_networks_json = json!({
341 network_name: example_network_json
342 });
343
344 let example_networks_json =
345 serde_json::to_string_pretty(&example_networks_json).unwrap();
346 warn!(
347 logger,
348 "Ignoring the 'defaults' field in dfx.json because project settings never apply to the shared network.\n\
349 To apply these settings to the shared network, define them in {shared_config_display_path} like so:\n\
350 {example_networks_json}",
351 shared_config_display_path = &shared_config_display_path,
352 example_networks_json = &example_networks_json
353 );
354 }
355 }
356}
357
358fn create_project_network_descriptor(
359 network_name: &str,
360 project_config: Option<Arc<Config>>,
361 local_bind_determination: &LocalBindDetermination,
362 logger: &Logger,
363) -> Option<Result<NetworkDescriptor, NetworkConfigError>> {
364 if let Some(config) = project_config {
365 if let Some(config_network) = config.get_config().get_network(network_name) {
366 info!(
367 logger,
368 "Using project-specific network '{}' defined in {}",
369 network_name,
370 config.get_path().display(),
371 );
372
373 let temp_path = match config.get_temp_path() {
374 Ok(temp_path) => temp_path,
375 Err(e) => {
376 return Some(Err(NetworkConfigError::GetTempPath(e)));
377 }
378 };
379 let data_directory = temp_path.join("network").join(network_name);
380 let legacy_pid_path = Some(temp_path.join("pid"));
381 let ephemeral_wallet_config_path = temp_path.join("local").join(WALLET_CONFIG_FILENAME);
382 Some(config_network_to_network_descriptor(
383 network_name,
384 config_network,
385 Some(config.get_config().get_defaults()),
386 data_directory,
387 LocalNetworkScopeDescriptor::Project,
388 Some(ephemeral_wallet_config_path),
389 local_bind_determination,
390 DEFAULT_PROJECT_LOCAL_BIND,
391 legacy_pid_path,
392 ))
393 } else {
394 debug!(
395 logger,
396 "There is no project-specific network '{}' defined in {}",
397 network_name,
398 config.get_path().display()
399 );
400 None
401 }
402 } else {
403 debug!(
404 logger,
405 "There is no project-specific network '{}' because there is no project (no dfx.json).",
406 network_name
407 );
408 None
409 }
410}
411
412fn create_default_network_from_name(
413 network_name: &str,
414 logger: &Logger,
415) -> Option<NetworkDescriptor> {
416 match network_name {
417 PLAYGROUND_NETWORK_NAME => {
418 debug!(logger, "Using default definition for network 'playground'.");
419 Some(NetworkDescriptor::default_playground_network())
420 }
421 _ => None,
422 }
423}
424
425fn get_local_bind_address(
426 local_provider: &ConfigLocalProvider,
427 local_bind_determination: &LocalBindDetermination,
428 data_directory: &Path,
429 default_local_bind: &str,
430) -> Result<String, NetworkConfigError> {
431 match local_bind_determination {
432 LocalBindDetermination::AsConfigured => Ok(local_provider
433 .bind
434 .clone()
435 .unwrap_or_else(|| default_local_bind.to_string())),
436 LocalBindDetermination::ApplyRunningWebserverPort => {
437 get_running_webserver_bind_address(data_directory, local_provider, default_local_bind)
438 }
439 }
440}
441
442fn get_running_webserver_bind_address(
443 data_directory: &Path,
444 local_provider: &ConfigLocalProvider,
445 default_local_bind: &str,
446) -> Result<String, NetworkConfigError> {
447 let local_bind = local_provider
448 .bind
449 .clone()
450 .unwrap_or_else(|| default_local_bind.to_string());
451 let path = data_directory.join("webserver-port");
452 if path.exists() {
453 let s = crate::fs::read_to_string(&path).map_err(ReadWebserverPortFailed)?;
454 let s = s.trim();
455 if s.is_empty() {
456 Ok(local_bind)
457 } else {
458 let port = s
459 .parse::<u16>()
460 .map_err(|e| ParsePortValueFailed(Box::new(path), Box::new(e)))?;
461 let host = match local_bind.rfind(':') {
465 None => local_bind.clone(),
466 Some(index) => local_bind[0..index].to_string(),
467 };
468 Ok(format!("{host}:{port}"))
469 }
470 } else {
471 Ok(local_bind)
472 }
473}
474
475pub fn command_line_provider_to_url(s: &str) -> Result<String, NetworkConfigError> {
476 match parse_provider_url(s) {
477 Ok(url) => Ok(url),
478 Err(original_error) => {
479 let prefixed_with_http = format!("http://{s}");
480 parse_provider_url(&prefixed_with_http).or(Err(original_error))
481 }
482 }
483}
484
485pub fn parse_provider_url(url: &str) -> Result<String, NetworkConfigError> {
486 Url::parse(url)
487 .map(|_| String::from(url))
488 .map_err(|e| ParseProviderUrlFailed(Box::new(url.to_string()), e))
489}
490
491#[cfg(test)]
492mod tests {
493 use super::*;
494 use crate::config::model::bitcoin_adapter::BitcoinAdapterLogLevel;
495 use crate::config::model::canister_http_adapter::HttpAdapterLogLevel;
496 use crate::config::model::dfinity::ReplicaSubnetType::{System, VerifiedApplication};
497 use crate::config::model::dfinity::{
498 ConfigDefaultsBitcoin, ConfigDefaultsCanisterHttp, ConfigDefaultsReplica, ReplicaLogLevel,
499 to_socket_addr,
500 };
501 use std::fs;
502 use std::net::SocketAddr;
503 use std::str::FromStr;
504
505 #[test]
506 fn use_default_if_no_webserver_port_file() {
507 test_with_webserver_port_file_contents(
509 LocalBindDetermination::ApplyRunningWebserverPort,
510 None,
511 "localhost:8000",
512 );
513 }
514
515 #[test]
516 fn ignore_running_webserver_port_if_not_requested() {
517 test_with_webserver_port_file_contents(
519 LocalBindDetermination::AsConfigured,
520 Some("1234"),
521 "localhost:8000",
522 );
523 }
524
525 #[test]
526 fn use_port_if_have_file() {
527 test_with_webserver_port_file_contents(
529 LocalBindDetermination::ApplyRunningWebserverPort,
530 Some("1234"),
531 "localhost:1234",
532 );
533 }
534
535 #[test]
536 fn ignore_port_if_not_requested() {
537 test_with_webserver_port_file_contents(
539 LocalBindDetermination::AsConfigured,
540 Some("1234"),
541 "localhost:8000",
542 );
543 }
544
545 #[test]
546 fn extra_whitespace_in_webserver_port_is_ok() {
547 test_with_webserver_port_file_contents(
549 LocalBindDetermination::ApplyRunningWebserverPort,
550 Some(" \n3456 \n"),
551 "localhost:3456",
552 );
553 }
554
555 #[test]
556 fn use_running_webserver_address() {
557 test_with_webserver_port_file_contents(
559 LocalBindDetermination::ApplyRunningWebserverPort,
560 None,
561 "localhost:8000",
562 );
563 }
564
565 #[test]
566 fn ignore_empty_webserver_port_file() {
567 test_with_webserver_port_file_contents(
569 LocalBindDetermination::ApplyRunningWebserverPort,
570 Some(""),
571 "localhost:8000",
572 );
573 }
574 #[test]
575 fn ignore_whitespace_only_webserver_port_file() {
576 test_with_webserver_port_file_contents(
578 LocalBindDetermination::ApplyRunningWebserverPort,
579 Some("\n"),
580 "localhost:8000",
581 );
582 }
583
584 fn test_with_webserver_port_file_contents(
585 local_bind_determination: LocalBindDetermination,
586 webserver_port_contents: Option<&str>,
587 expected_socket_addr: &str,
588 ) {
589 let temp_dir = tempfile::tempdir().unwrap();
590 let project_dir = temp_dir.path().join("project");
591 fs::create_dir_all(&project_dir).unwrap();
592 let project_dfx_json = project_dir.join("dfx.json");
593 std::fs::write(
594 project_dfx_json,
595 r#"{
596 "networks": {
597 "local": {
598 "bind": "localhost:8000"
599 }
600 }
601 }"#,
602 )
603 .unwrap();
604
605 if let Some(webserver_port_contents) = webserver_port_contents {
606 let dot_dfx_dir = project_dir.join(".dfx");
607 let network_data_dir = dot_dfx_dir.join("network").join("local");
608 fs::create_dir_all(&network_data_dir).unwrap();
609 std::fs::write(
610 network_data_dir.join("webserver-port"),
611 webserver_port_contents,
612 )
613 .unwrap();
614 }
615
616 let config = Config::from_dir(&project_dir, None).unwrap().unwrap();
617 let network_descriptor = create_network_descriptor(
618 Some(Arc::new(config)),
619 Arc::new(NetworksConfig::new().unwrap()),
620 None,
621 None,
622 local_bind_determination,
623 )
624 .unwrap();
625
626 assert_eq!(
627 network_descriptor
628 .local_server_descriptor()
629 .unwrap()
630 .bind_address,
631 to_socket_addr(expected_socket_addr).unwrap()
632 );
633 }
634
635 #[test]
636 fn config_with_local_bind_addr() {
637 let config = Config::from_str(
638 r#"{
639 "networks": {
640 "local": {
641 "bind": "localhost:8000"
642 }
643 }
644 }"#,
645 )
646 .unwrap();
647
648 let network_descriptor = create_network_descriptor(
649 Some(Arc::new(config)),
650 Arc::new(NetworksConfig::new().unwrap()),
651 None,
652 None,
653 LocalBindDetermination::AsConfigured,
654 )
655 .unwrap();
656
657 assert_eq!(
658 network_descriptor
659 .local_server_descriptor()
660 .unwrap()
661 .bind_address,
662 to_socket_addr("localhost:8000").unwrap()
663 );
664 }
665
666 #[test]
667 fn config_with_invalid_local_bind_addr() {
668 let config = Config::from_str(
669 r#"{
670 "networks": {
671 "local": {
672 "bind": "not a valid bind address"
673 }
674 }
675 }"#,
676 )
677 .unwrap();
678
679 let result = create_network_descriptor(
680 Some(Arc::new(config)),
681 Arc::new(NetworksConfig::new().unwrap()),
682 None,
683 None,
684 LocalBindDetermination::AsConfigured,
685 );
686 assert!(result.is_err());
687 }
688
689 #[test]
690 fn config_returns_local_bind_address_if_no_local_network() {
691 let config = Config::from_str(
692 r#"{
693 "networks": {
694 }
695 }"#,
696 )
697 .unwrap();
698 let network_descriptor = create_network_descriptor(
699 Some(Arc::new(config)),
700 Arc::new(NetworksConfig::new().unwrap()),
701 None,
702 None,
703 LocalBindDetermination::AsConfigured,
704 )
705 .unwrap();
706
707 assert_eq!(
708 network_descriptor
709 .local_server_descriptor()
710 .unwrap()
711 .bind_address,
712 to_socket_addr("127.0.0.1:4943").unwrap()
713 );
714 }
715
716 #[test]
717 fn config_returns_local_bind_address_if_no_networks() {
718 let config = Config::from_str(
719 r#"{
720 }"#,
721 )
722 .unwrap();
723 let network_descriptor = create_network_descriptor(
724 Some(Arc::new(config)),
725 Arc::new(NetworksConfig::new().unwrap()),
726 None,
727 None,
728 LocalBindDetermination::AsConfigured,
729 )
730 .unwrap();
731
732 assert_eq!(
733 network_descriptor
734 .local_server_descriptor()
735 .unwrap()
736 .bind_address,
737 to_socket_addr("127.0.0.1:4943").unwrap()
738 );
739 }
740
741 #[test]
742 fn get_bitcoin_config() {
743 let config = Config::from_str(
744 r#"{
745 "defaults": {
746 "bitcoin": {
747 "enabled": true,
748 "nodes": ["127.0.0.1:18444"],
749 "log_level": "info"
750 }
751 },
752 "networks": {
753 "local": {
754 "bind": "localhost:8000"
755 }
756 }
757 }"#,
758 )
759 .unwrap();
760
761 let network_descriptor = create_network_descriptor(
762 Some(Arc::new(config)),
763 Arc::new(NetworksConfig::new().unwrap()),
764 None,
765 None,
766 LocalBindDetermination::AsConfigured,
767 )
768 .unwrap();
769 let bitcoin_config = &network_descriptor
770 .local_server_descriptor()
771 .unwrap()
772 .bitcoin;
773
774 assert_eq!(
775 bitcoin_config,
776 &ConfigDefaultsBitcoin {
777 enabled: true,
778 nodes: Some(vec![SocketAddr::from_str("127.0.0.1:18444").unwrap()]),
779 log_level: BitcoinAdapterLogLevel::Info,
780 ..ConfigDefaultsBitcoin::default()
781 }
782 );
783 }
784
785 #[test]
786 fn get_bitcoin_config_default_log_level() {
787 let config = Config::from_str(
788 r#"{
789 "defaults": {
790 "bitcoin": {
791 "enabled": true,
792 "nodes": ["127.0.0.1:18444"]
793 }
794 },
795 "networks": {
796 "local": {
797 "bind": "localhost:8000"
798 }
799 }
800 }"#,
801 )
802 .unwrap();
803
804 let network_descriptor = create_network_descriptor(
805 Some(Arc::new(config)),
806 Arc::new(NetworksConfig::new().unwrap()),
807 None,
808 None,
809 LocalBindDetermination::AsConfigured,
810 )
811 .unwrap();
812 let bitcoin_config = &network_descriptor
813 .local_server_descriptor()
814 .unwrap()
815 .bitcoin;
816
817 assert_eq!(
818 bitcoin_config,
819 &ConfigDefaultsBitcoin {
820 enabled: true,
821 nodes: Some(vec![SocketAddr::from_str("127.0.0.1:18444").unwrap()]),
822 log_level: BitcoinAdapterLogLevel::Info, ..ConfigDefaultsBitcoin::default()
824 }
825 );
826 }
827
828 #[test]
829 fn get_bitcoin_config_debug_log_level() {
830 let config = Config::from_str(
831 r#"{
832 "defaults": {
833 "bitcoin": {
834 "enabled": true,
835 "log_level": "debug"
836 }
837 },
838 "networks": {
839 "local": {
840 "bind": "localhost:8000"
841 }
842 }
843 }"#,
844 )
845 .unwrap();
846
847 let network_descriptor = create_network_descriptor(
848 Some(Arc::new(config)),
849 Arc::new(NetworksConfig::new().unwrap()),
850 None,
851 None,
852 LocalBindDetermination::AsConfigured,
853 )
854 .unwrap();
855 let bitcoin_config = &network_descriptor
856 .local_server_descriptor()
857 .unwrap()
858 .bitcoin;
859
860 assert_eq!(
861 bitcoin_config,
862 &ConfigDefaultsBitcoin {
863 enabled: true,
864 log_level: BitcoinAdapterLogLevel::Debug,
865 ..ConfigDefaultsBitcoin::default()
866 }
867 );
868 }
869
870 #[test]
871 fn bitcoin_config_on_local_network() {
872 let config = Config::from_str(
873 r#"{
874 "networks": {
875 "local": {
876 "bind": "127.0.0.1:8000",
877 "bitcoin": {
878 "enabled": true,
879 "nodes": ["127.0.0.1:18444"],
880 "log_level": "info"
881 }
882 }
883 }
884 }"#,
885 )
886 .unwrap();
887
888 let network_descriptor = create_network_descriptor(
889 Some(Arc::new(config)),
890 Arc::new(NetworksConfig::new().unwrap()),
891 None,
892 None,
893 LocalBindDetermination::AsConfigured,
894 )
895 .unwrap();
896 let bitcoin_config = &network_descriptor
897 .local_server_descriptor()
898 .unwrap()
899 .bitcoin;
900
901 assert_eq!(
902 bitcoin_config,
903 &ConfigDefaultsBitcoin {
904 enabled: true,
905 nodes: Some(vec![SocketAddr::from_str("127.0.0.1:18444").unwrap()]),
906 log_level: BitcoinAdapterLogLevel::Info,
907 ..ConfigDefaultsBitcoin::default()
908 }
909 );
910 }
911
912 #[test]
913 fn replica_config_on_local_network() {
914 let config = Config::from_str(
915 r#"{
916 "networks": {
917 "local": {
918 "bind": "127.0.0.1:8000",
919 "replica": {
920 "subnet_type": "verifiedapplication",
921 "port": 17001,
922 "log_level": "trace"
923 }
924 }
925 }
926 }"#,
927 )
928 .unwrap();
929
930 let network_descriptor = create_network_descriptor(
931 Some(Arc::new(config)),
932 Arc::new(NetworksConfig::new().unwrap()),
933 None,
934 None,
935 LocalBindDetermination::AsConfigured,
936 )
937 .unwrap();
938 let replica_config = &network_descriptor
939 .local_server_descriptor()
940 .unwrap()
941 .replica;
942
943 assert_eq!(
944 replica_config,
945 &ConfigDefaultsReplica {
946 subnet_type: Some(VerifiedApplication),
947 port: Some(17001),
948 log_level: Some(ReplicaLogLevel::Trace)
949 }
950 );
951 }
952
953 #[test]
954 fn replica_config_on_local_network_overrides_default() {
955 let config = Config::from_str(
959 r#"{
960 "defaults": {
961 "replica": {
962 "port": 13131
963 }
964 },
965 "networks": {
966 "local": {
967 "bind": "127.0.0.1:8000",
968 "replica": {
969 "subnet_type": "system"
970 }
971 }
972 }
973 }"#,
974 )
975 .unwrap();
976
977 let network_descriptor = create_network_descriptor(
978 Some(Arc::new(config)),
979 Arc::new(NetworksConfig::new().unwrap()),
980 None,
981 None,
982 LocalBindDetermination::AsConfigured,
983 )
984 .unwrap();
985 let replica_config = &network_descriptor
986 .local_server_descriptor()
987 .unwrap()
988 .replica;
989
990 assert_eq!(
991 replica_config,
992 &ConfigDefaultsReplica {
993 subnet_type: Some(System),
994 port: None,
995 log_level: None
996 }
997 );
998 }
999
1000 #[test]
1001 #[cfg_attr(target_os = "macos", ignore)]
1004 fn canister_http_config_on_local_network() {
1005 let config = Config::from_str(
1006 r#"{
1007 "networks": {
1008 "local": {
1009 "bind": "127.0.0.1:8000",
1010 "canister_http": {
1011 "enabled": true,
1012 "log_level": "debug"
1013 }
1014 }
1015 }
1016 }"#,
1017 )
1018 .unwrap();
1019
1020 let network_descriptor = create_network_descriptor(
1021 Some(Arc::new(config)),
1022 Arc::new(NetworksConfig::new().unwrap()),
1023 None,
1024 None,
1025 LocalBindDetermination::AsConfigured,
1026 )
1027 .unwrap();
1028 let canister_http_config = &network_descriptor
1029 .local_server_descriptor()
1030 .unwrap()
1031 .canister_http;
1032
1033 assert_eq!(
1034 canister_http_config,
1035 &ConfigDefaultsCanisterHttp {
1036 enabled: true,
1037 log_level: HttpAdapterLogLevel::Debug
1038 }
1039 );
1040 }
1041
1042 #[test]
1043 fn url_is_url() {
1044 assert_eq!(
1045 command_line_provider_to_url("http://127.0.0.1:8000").unwrap(),
1046 "http://127.0.0.1:8000"
1047 );
1048 }
1049
1050 #[test]
1051 fn addr_and_port_to_url() {
1052 assert_eq!(
1053 command_line_provider_to_url("127.0.0.1:8000").unwrap(),
1054 "http://127.0.0.1:8000"
1055 );
1056 }
1057}