cf_env/
lib.rs

1//! Easy and typed abstraction on Cloud Foundry Environment variables
2//!
3//! It allows you to get:
4//! - Services, optionally filtered by name or type
5//! - Application infos
6//! - Cloud Foundry app instance set variables, most of the times starting with `CF_`
7//!
8//! It's meant to get you away from boilerplating and get you started with typed variables while keeping simplicity
9#![deny(clippy::all, clippy::cargo)]
10#![forbid(unsafe_code)]
11
12pub mod constants;
13pub mod enums;
14pub mod models;
15
16#[doc(hidden)]
17pub use constants::*;
18#[doc(hidden)]
19pub use enums::*;
20#[doc(hidden)]
21pub use models::*;
22
23use guid_create::GUID;
24use http::Uri;
25use locale_types::Locale;
26use serde::de::DeserializeOwned;
27use std::collections::HashMap;
28use std::env;
29use std::net::{IpAddr, SocketAddr};
30use std::panic;
31use std::path::PathBuf;
32use std::str::FromStr;
33
34/// Checks if `VCAP_APPLICATION` is defined, if so uses as the indicator that the app is running in a Cloud Foundry Environment.
35///
36/// Use this with caution. To use the flexibility of cargo and optimization of rust and llvm you should only use this if there is no other way. One other possible way would be to use features flags for your binaries and use them to identify for which environment you build.
37pub fn is_cf_env() -> bool {
38    env::var(VCAP_APPLICATION).is_ok()
39}
40
41/// Get's the value from `CF_INSTANCE_ADDR` as a typed SocketAddr
42pub fn get_instance_address() -> Result<SocketAddr, Error<'static>> {
43    match env::var(CF_INSTANCE_ADDR) {
44        Ok(addr_string) => match addr_string.parse::<SocketAddr>() {
45            Ok(socket) => Ok(socket),
46            Err(_) => Err(Error::EnvMalformed(
47                CF_INSTANCE_ADDR.to_string(),
48                "Doesn't match the format of addr:ip".to_string(),
49            )),
50        },
51        Err(_) => Err(Error::EnvNotSet(CF_INSTANCE_ADDR)),
52    }
53}
54
55/// Get's the value from `CF_INSTANCE_GUID` as a typed GUID
56pub fn get_instance_guid() -> Result<GUID, Error<'static>> {
57    match env::var(CF_INSTANCE_GUID) {
58        Ok(guid_string) => match GUID::parse(&guid_string) {
59            Ok(result) => Ok(result),
60            Err(_) => Err(Error::EnvMalformed(
61                CF_INSTANCE_GUID.to_string(),
62                "Isn't a valid guid".to_string(),
63            )),
64        },
65        Err(_) => Err(Error::EnvNotSet(CF_INSTANCE_GUID)),
66    }
67}
68
69/// Get's the value from `CF_INSTANCE_INDEX` as a typed u128
70pub fn get_instance_index() -> Result<u128, Error<'static>> {
71    match env::var(CF_INSTANCE_INDEX) {
72        Ok(index_string) => match index_string.parse::<u128>() {
73            Ok(result) => Ok(result),
74            Err(_) => Err(Error::EnvMalformed(
75                CF_INSTANCE_INDEX.to_string(),
76                "Ins't a valid positive (u128) number".to_string(),
77            )),
78        },
79        Err(_) => Err(Error::EnvNotSet(CF_INSTANCE_INDEX)),
80    }
81}
82
83/// Get's the value from `CF_INSTANCE_IP` as a typed IpAddr
84pub fn get_instance_ip() -> Result<IpAddr, Error<'static>> {
85    match env::var(CF_INSTANCE_IP) {
86        Ok(ip_string) => match ip_string.parse::<IpAddr>() {
87            Ok(result) => Ok(result),
88            Err(_) => Err(Error::EnvMalformed(
89                CF_INSTANCE_IP.to_string(),
90                "Ins't a valid ip address".to_string(),
91            )),
92        },
93        Err(_) => Err(Error::EnvNotSet(CF_INSTANCE_IP)),
94    }
95}
96
97/// Get's the value from `CF_INSTANCE_INTERNAL_IP` as a typed IpAddr
98pub fn get_instance_internal_ip() -> Result<IpAddr, Error<'static>> {
99    match env::var(CF_INSTANCE_INTERNAL_IP) {
100        Ok(ip_string) => match ip_string.parse::<IpAddr>() {
101            Ok(result) => Ok(result),
102            Err(_) => Err(Error::EnvMalformed(
103                CF_INSTANCE_INTERNAL_IP.to_string(),
104                "Ins't a valid ip address".to_string(),
105            )),
106        },
107        Err(_) => Err(Error::EnvNotSet(CF_INSTANCE_INTERNAL_IP)),
108    }
109}
110
111/// Get's the value from `CF_INSTANCE_PORT` as a typed u16
112pub fn get_instance_port() -> Result<u16, Error<'static>> {
113    match env::var(CF_INSTANCE_PORT) {
114        Ok(index_string) => match index_string.parse::<u16>() {
115            Ok(result) => Ok(result),
116            Err(_) => Err(Error::EnvMalformed(
117                CF_INSTANCE_PORT.to_string(),
118                "Ins't a valid positive (u16) number".to_string(),
119            )),
120        },
121        Err(_) => Err(Error::EnvNotSet(CF_INSTANCE_PORT)),
122    }
123}
124
125/// Get's the value from `DATABASE_URL` as a typed Uri
126pub fn get_database_url() -> Result<Uri, Error<'static>> {
127    match env::var(DATABASE_URL) {
128        Ok(index_string) => match index_string.parse::<Uri>() {
129            Ok(result) => Ok(result),
130            Err(_) => Err(Error::EnvMalformed(
131                DATABASE_URL.to_string(),
132                "Ins't a valid uri".to_string(),
133            )),
134        },
135        Err(_) => Err(Error::EnvNotSet(DATABASE_URL)),
136    }
137}
138
139/// Get's the value from `HOME` as a typed PathBuf
140pub fn get_home() -> Result<PathBuf, Error<'static>> {
141    match env::var(HOME) {
142        Ok(home_string) => Ok(PathBuf::from(home_string)),
143        Err(_) => Err(Error::EnvNotSet(HOME)),
144    }
145}
146
147/// Get's the value from `LANG` as a typed Locale
148pub fn get_lang() -> Result<Locale, Error<'static>> {
149    match env::var(LANG) {
150        Ok(lang_string) => {
151            let parse_result = panic::catch_unwind(|| Locale::from_str(&lang_string));
152
153            if parse_result.is_err() {
154                return Err(Error::EnvMalformed(
155                    LANG.to_string(),
156                    "Ins't a valid locale".to_string(),
157                ));
158            }
159
160            match parse_result.unwrap() {
161                Ok(result) => Ok(result),
162                Err(_) => Err(Error::EnvMalformed(
163                    LANG.to_string(),
164                    "Ins't a valid locale".to_string(),
165                )),
166            }
167        }
168        Err(_) => Err(Error::EnvNotSet(LANG)),
169    }
170}
171
172/// Get's the value from `MEMORY_LIMIT` as a typed MemoryLimit
173pub fn get_memory_limit() -> Result<MemoryLimit, Error<'static>> {
174    match env::var(MEMORY_LIMIT) {
175        Ok(memory_string) => {
176            match MemoryLimit::from_string(memory_string, MEMORY_LIMIT.to_string()) {
177                Ok(result) => Ok(result),
178                Err(_) => Err(Error::EnvMalformed(
179                    MEMORY_LIMIT.to_string(),
180                    "Ins't a valid memory size formatted after '<size><unit>'".to_string(),
181                )),
182            }
183        }
184        Err(_) => Err(Error::EnvNotSet(MEMORY_LIMIT)),
185    }
186}
187
188/// Get's the value from `PORT` as a typed 16
189pub fn get_port() -> Result<u16, Error<'static>> {
190    match env::var(PORT) {
191        Ok(port_string) => match port_string.parse::<u16>() {
192            Ok(result) => Ok(result),
193            Err(_) => Err(Error::EnvMalformed(
194                PORT.to_string(),
195                "Ins't a valid positive (u16) number".to_string(),
196            )),
197        },
198        Err(_) => Err(Error::EnvNotSet(PORT)),
199    }
200}
201
202/// Get's the value from `PWD` as a typed PathBuf
203pub fn get_pwd() -> Result<PathBuf, Error<'static>> {
204    match env::var(PWD) {
205        Ok(pwd_string) => Ok(PathBuf::from(pwd_string)),
206        Err(_) => Err(Error::EnvNotSet(PWD)),
207    }
208}
209
210/// Get's the value from `TMPDIR` as a typed PathBuf
211pub fn get_tmp_dir() -> Result<PathBuf, Error<'static>> {
212    match env::var(TMPDIR) {
213        Ok(tmp_dir) => Ok(PathBuf::from(tmp_dir)),
214        Err(_) => Err(Error::EnvNotSet(TMPDIR)),
215    }
216}
217
218/// Get's the value from `USER`
219pub fn get_user() -> Result<String, Error<'static>> {
220    match env::var(USER) {
221        Ok(user_string) => Ok(user_string),
222        Err(_) => Err(Error::EnvNotSet(USER)),
223    }
224}
225
226type ServiceMap = HashMap<String, Vec<Service>>;
227
228/// Get's the value from `VCAP_SERVICES` as a typed HashMap of Strings and a list of Services
229pub fn get_services() -> Result<ServiceMap, Error<'static>> {
230    match env::var(VCAP_SERVICES) {
231        Ok(services) => match serde_json::from_str::<ServiceMap>(&services) {
232            Ok(value) => Ok(value),
233            Err(_err) => Err(Error::JsonMalformed(VCAP_SERVICES.to_string())),
234        },
235        Err(_) => Err(Error::EnvNotSet(VCAP_SERVICES)),
236    }
237}
238
239/// Get's you a single service from`VCAP_SERVICES` by it's name
240///
241/// This allows you to get a service with it's credentials. The type `T` can be used to have a typed credentials struct. As the format of credentials is up to your provider it defaults to a generic Value from serde_json.
242///
243/// ```no_run
244/// use serde::{Serialize, Deserialize};
245///
246/// #[derive(Serialize, Deserialize)]
247/// pub struct CustomCredentials {
248///     pub password: String,
249///     pub username: String,
250///     pub host: String,
251///     pub port: u16,
252/// }
253///
254/// // After that you can use it
255///
256/// let service = cf_env::get_service_by_name::<CustomCredentials>("my_db").unwrap();
257/// ```
258///
259/// There is no need for typed credentials if you would like to parse it anyway
260///
261/// ```no_run
262/// use serde_json::Value;
263/// use cf_env::Service;
264///
265/// let service: Service<Value> = cf_env::get_service_by_name("my_db").unwrap();
266///
267/// let uri = service.credentials["uri"].as_str().unwrap();
268/// ```
269pub fn get_service_by_name<T>(name: &str) -> Result<Service<T>, Error>
270where
271    T: DeserializeOwned,
272{
273    match get_services() {
274        Ok(services) => {
275            for key in services.keys() {
276                for service in services.get(key).unwrap().iter() {
277                    if service.name == name {
278                        let service_json = serde_json::to_string(service).unwrap();
279                        match serde_json::from_str::<Service<T>>(&service_json) {
280                            Ok(service) => return Ok(service),
281                            Err(_) => {
282                                return Err(Error::JsonMalformed(format!(
283                                    "{}.credentials",
284                                    service.name.to_owned()
285                                )))
286                            }
287                        }
288                    }
289                }
290            }
291            Err(Error::ServiceNotPresent(name))
292        }
293        Err(e) => Err(e),
294    }
295}
296
297/// Get's you a a list services from`VCAP_SERVICES` by their type
298///
299/// This allows you to get the services with their credentials. The type `T` can be used to have a typed credentials struct. As the format of credentials is up to your provider it defaults to a generic Value from serde_json.
300///
301/// ```no_run
302/// use serde::{Serialize, Deserialize};
303///
304/// #[derive(Serialize, Deserialize)]
305/// pub struct CustomCredentials {
306///     pub password: String,
307///     pub username: String,
308///     pub host: String,
309///     pub port: u16,
310/// }
311///
312/// // After that you can use it
313///
314/// let services = cf_env::get_services_by_type::<CustomCredentials>("a_type_of_service").unwrap();
315/// ```
316///
317/// There is no need for typed credentials if you would like to parse it anyway
318///
319/// ```no_run
320/// use serde_json::Value;
321/// use cf_env::Service;
322///
323/// let services: Vec<Service<Value>>  = cf_env::get_services_by_type("a_type_of_service").unwrap();
324///
325/// let uri = services[0].credentials["uri"].as_str().unwrap();
326/// ```
327pub fn get_services_by_type<T>(type_name: &str) -> Result<Vec<Service<T>>, Error>
328where
329    T: DeserializeOwned,
330{
331    match get_services() {
332        Ok(services) => {
333            if services.get(type_name).is_some() {
334                let service_json = serde_json::to_string(services.get(type_name).unwrap()).unwrap();
335                match serde_json::from_str::<Vec<Service<T>>>(&service_json) {
336                    Ok(service) => return Ok(service),
337                    Err(_err) => {
338                        return Err(Error::JsonMalformed(format!("<{type_name}>.credentials")))
339                    }
340                }
341            }
342            Err(Error::ServiceTypeNotPresent(type_name))
343        }
344        Err(e) => Err(e),
345    }
346}
347
348/// Get's you the information from `VCAP_APPLICATION` as a typed Application
349pub fn get_application_info() -> Result<Application, Error<'static>> {
350    match env::var(VCAP_APPLICATION) {
351        Ok(application) => match serde_json::from_str::<Application>(&application) {
352            Ok(value) => Ok(value),
353            Err(_err) => Err(Error::JsonMalformed(VCAP_APPLICATION.to_string())),
354        },
355        Err(_) => Err(Error::EnvNotSet(VCAP_APPLICATION)),
356    }
357}
358
359#[cfg(test)]
360mod tests {
361
362    const SERVICE_DATA: &str = "
363    {
364        \"secure-auth\": [
365          {
366            \"label\": \"secure-auth\",
367            \"provider\": null,
368            \"plan\": \"beta\",
369            \"name\": \"my-app-backend-auth\",
370            \"tags\": [
371              \"oidc\",
372              \"jwt\"
373            ],
374            \"instance_guid\": \"720a4210-3ea0-44e0-b3e3-63ad833191a9\",
375            \"instance_name\": \"my-app-backend-auth\",
376            \"binding_guid\": \"8d2b186f-22a6-48a8-bb38-df5320987812\",
377            \"binding_name\": null,
378            \"credentials\": {
379              \"authorizationEndpoint\": \"https://authority.example.io/intern/authorize\",
380              \"clientId\": \"VEO7igWPLpRIzB9IDoUAXhbsowklLn8u93hYyOYSBbPANMiLE5UGo0wpqdasHTDNdP\",
381              \"clientSecret\": \"null\",
382              \"accessTokenValidity\": \"900\",
383              \"tokenEndpoint\": \"https://authority.example.io/intern/token\",
384              \"userInfoEndpoint\": \"https://authority.example.io/userinfo\",
385              \"logoutEndpoint\": \"https://authority.example.io/logout\",
386              \"redirectUris\": \"https://memory-service.example.io/oidc/callback,http://localhost:8080/oidc/callback\",
387              \"grantTypes\": \"client_credentials\"
388            },
389            \"syslog_drain_url\": null,
390            \"volume_mounts\": []
391          }
392        ],
393        \"mongodb\": [
394          {
395            \"label\": \"mongodb\",
396            \"provider\": null,
397            \"plan\": \"huge\",
398            \"name\": \"my-db\",
399            \"tags\": [
400              \"mongodb\",
401              \"mongo\"
402            ],
403            \"instance_guid\": \"2b6e08f9-3174-46ff-999d-183dc4c4964d\",
404            \"instance_name\": \"lpn-db\",
405            \"binding_guid\": \"3290823d-ab9f-4d72-b414-2438144ea9dc\",
406            \"binding_name\": null,
407            \"credentials\": {
408              \"host\": \"b4386ed6-2770-444e-9a5d-727855f758fa.services.intern\",
409              \"port\": \"27801\",
410              \"database\": \"rs_e01562b7-04e7-46fb-b348-03fb70d442f8\",
411              \"username\": \"598bd0f7-9b35-42df-a504-e1964f2698f4\",
412              \"password\": \"olskjlkjasf09823ja0a\",
413              \"database_uri\": \"mongodb://598bd0f7-9b35-42df-a504-e1964f2698f4:olskjlkjasf09823ja0a@b4386ed6-2770-444e-9a5d-727855f758fa.services.intern:37831\",
414              \"uri\": \"mongodb://598bd0f7-9b35-42df-a504-e1964f2698f4:olskjlkjasf09823ja0a@b4386ed6-2770-444e-9a5d-727855f758fa.services.intern:37831\",
415              \"replica_set\": \"rs_66a04559-c503-44f8-a2ef-28644b3cbce4\"
416            },
417            \"syslog_drain_url\": null,
418            \"volume_mounts\": []
419          }
420        ]
421      }";
422
423    const APP_DATA: &str = "
424      {
425        \"cf_api\": \"https://api.example.io\",
426        \"limits\": {
427          \"fds\": 12384,
428          \"mem\": 512,
429          \"disk\": 1024
430        },
431        \"application_name\": \"my-backend\",
432        \"application_uris\": [
433          \"backend.example.io\"
434        ],
435        \"name\": \"my-backend\",
436        \"space_name\": \"production\",
437        \"space_id\": \"29349a46-ff0c-447e-bde0-db1be814f564\",
438        \"organization_id\": \"26421037-ab23-4b51-99f8-9f5a6251fd26\",
439        \"organization_name\": \"Project_One\",
440        \"uris\": [
441          \"backend.example.io\"
442        ],
443        \"users\": null,
444        \"process_id\": \"d8304a62-2df7-41d5-9211-0917c2253591\",
445        \"process_type\": \"web\",
446        \"application_id\": \"d8304a62-2df7-41d5-9211-0917c2253591\",
447        \"version\": \"9fe9fe07-c7b7-415b-afa3-75fef5258d47\",
448        \"application_version\": \"9fe9fe07-c7b7-415b-afa3-75fef5258d47\"
449      }";
450
451    #[test]
452    fn get_instance_addr_valid() {
453        std::env::set_var("CF_INSTANCE_ADDR", "10.24.8.2:8080");
454        let instance_addr_result = crate::get_instance_address();
455
456        assert!(instance_addr_result.is_ok());
457
458        let instance_addr = instance_addr_result.unwrap();
459        assert_eq!(instance_addr.to_string(), "10.24.8.2:8080".to_string());
460        assert_eq!(
461            instance_addr.ip(),
462            "10.24.8.2".parse::<std::net::IpAddr>().unwrap()
463        );
464        assert_eq!(instance_addr.port(), 8080);
465    }
466
467    #[test]
468    fn get_instance_addr_invalid_port() {
469        std::env::set_var("CF_INSTANCE_ADDR", "10.24.8.2:port");
470        let instance_addr_result = crate::get_instance_address();
471
472        assert!(instance_addr_result.is_err());
473    }
474
475    #[test]
476    fn get_instance_addr_invalid_not_defined() {
477        std::env::remove_var(crate::CF_INSTANCE_ADDR);
478        let instance_addr_result = crate::get_instance_address();
479
480        assert!(instance_addr_result.is_err());
481    }
482
483    #[test]
484    fn get_instance_addr_invalid_host() {
485        std::env::set_var("CF_INSTANCE_ADDR", "host:8080");
486        let instance_addr_result = crate::get_instance_address();
487
488        assert!(instance_addr_result.is_err());
489    }
490
491    #[test]
492    fn get_guid_valid() {
493        std::env::set_var("CF_INSTANCE_GUID", "046463bc-1ba9-4046-bf5a-bd95672ee871");
494        let guid_result = crate::get_instance_guid();
495
496        assert!(guid_result.is_ok());
497        assert_eq!(
498            guid_result.unwrap(),
499            guid_create::GUID::parse("046463bc-1ba9-4046-bf5a-bd95672ee871").unwrap()
500        );
501    }
502
503    #[test]
504    fn get_guid_invalid() {
505        std::env::set_var("CF_INSTANCE_GUID", "046463bc-1ba9-4046-bf5a-bd95672ee81");
506        let guid_result = crate::get_instance_guid();
507
508        assert!(guid_result.is_err());
509    }
510
511    #[test]
512    fn get_guid_invalid_not_defined() {
513        std::env::remove_var(crate::CF_INSTANCE_GUID);
514        let guid_result = crate::get_instance_guid();
515
516        assert!(guid_result.is_err());
517    }
518
519    #[test]
520    fn get_instance_index_valid() {
521        std::env::set_var("CF_INSTANCE_INDEX", "8");
522        let index_result = crate::get_instance_index();
523
524        assert!(index_result.is_ok());
525        assert_eq!(index_result.unwrap(), 8);
526    }
527
528    #[test]
529    fn get_instance_index_invalid_negative() {
530        std::env::set_var("CF_INSTANCE_INDEX", "-1");
531        let index_result = crate::get_instance_index();
532
533        assert!(index_result.is_err());
534    }
535
536    #[test]
537    fn get_instance_index_invalid_not_defined() {
538        std::env::remove_var(crate::CF_INSTANCE_INDEX);
539        let index_result = crate::get_instance_index();
540
541        assert!(index_result.is_err());
542    }
543
544    #[test]
545    fn get_instance_index_invalid_non_number() {
546        std::env::set_var("CF_INSTANCE_INDEX", "hello");
547        let index_result = crate::get_instance_index();
548
549        assert!(index_result.is_err());
550    }
551
552    #[test]
553    fn get_instance_ip_invalid_domain() {
554        std::env::set_var("CF_INSTANCE_IP", "me.com");
555        let index_result = crate::get_instance_ip();
556
557        assert!(index_result.is_err());
558    }
559
560    #[test]
561    fn get_instance_ip_invalid_not_defined() {
562        std::env::remove_var(crate::CF_INSTANCE_IP);
563        let index_result = crate::get_instance_ip();
564
565        assert!(index_result.is_err());
566    }
567
568    #[test]
569    fn get_instance_ip_invalid_ip() {
570        std::env::set_var("CF_INSTANCE_IP", "670.120.01.94");
571        let index_result = crate::get_instance_ip();
572
573        assert!(index_result.is_err());
574    }
575
576    #[test]
577    fn get_instance_ip_valid() {
578        std::env::set_var("CF_INSTANCE_IP", "192.168.2.3");
579        let index_result = crate::get_instance_ip();
580
581        assert!(index_result.is_ok());
582        assert_eq!(index_result.unwrap().to_string(), "192.168.2.3".to_string());
583    }
584
585    #[test]
586    fn get_instance_internal_ip_invalid_domain() {
587        std::env::set_var("CF_INSTANCE_INTERNAL_IP", "me.com");
588        let index_result = crate::get_instance_internal_ip();
589
590        assert!(index_result.is_err());
591    }
592
593    #[test]
594    fn get_instance_internal_ip_invalid_not_defined() {
595        std::env::remove_var(crate::CF_INSTANCE_INTERNAL_IP);
596        let index_result = crate::get_instance_internal_ip();
597
598        assert!(index_result.is_err());
599    }
600
601    #[test]
602    fn get_instance_internal_ip_invalid_ip() {
603        std::env::set_var("CF_INSTANCE_INTERNAL_IP", "670.120.01.94");
604        let index_result = crate::get_instance_internal_ip();
605
606        assert!(index_result.is_err());
607    }
608
609    #[test]
610    fn get_instance_internal_ip_valid() {
611        std::env::set_var("CF_INSTANCE_INTERNAL_IP", "192.168.2.3");
612        let index_result = crate::get_instance_internal_ip();
613
614        assert!(index_result.is_ok());
615        assert_eq!(index_result.unwrap().to_string(), "192.168.2.3".to_string());
616    }
617
618    #[test]
619    fn get_instance_port_valid() {
620        std::env::set_var("CF_INSTANCE_PORT", "8080");
621        let port_result = crate::get_instance_port();
622
623        assert!(port_result.is_ok());
624        assert_eq!(port_result.unwrap(), 8080);
625    }
626
627    #[test]
628    fn get_instance_port_invalid() {
629        std::env::set_var("CF_INSTANCE_PORT", "hello");
630        let port_result = crate::get_instance_port();
631
632        assert!(port_result.is_err());
633    }
634
635    #[test]
636    fn get_instance_port_invalid_not_defined() {
637        std::env::remove_var(crate::CF_INSTANCE_PORT);
638        let port_result = crate::get_instance_port();
639
640        assert!(port_result.is_err());
641    }
642
643    #[test]
644    fn get_port_valid() {
645        std::env::set_var("PORT", "8080");
646        let port_result = crate::get_port();
647
648        assert!(port_result.is_ok());
649        assert_eq!(port_result.unwrap(), 8080);
650    }
651
652    #[test]
653    fn get_port_invalid() {
654        std::env::set_var("PORT", "hello");
655        let port_result = crate::get_port();
656
657        assert!(port_result.is_err());
658    }
659
660    #[test]
661    fn get_port_invalid_not_defined() {
662        std::env::remove_var(crate::PORT);
663        let port_result = crate::get_port();
664
665        assert!(port_result.is_err());
666    }
667
668    #[test]
669    fn get_lang_valid() {
670        std::env::set_var("LANG", "en_US.UTF-8");
671        let lang_result = crate::get_lang();
672
673        assert!(lang_result.is_ok());
674        assert_eq!(lang_result.unwrap().to_string(), "en_US.UTF-8".to_string());
675    }
676
677    #[test]
678    fn get_lang_invalid() {
679        std::env::set_var("LANG", "hello");
680        let lang_result = crate::get_lang();
681
682        assert!(lang_result.is_err());
683    }
684
685    #[test]
686    fn get_lang_invalid_not_defined() {
687        std::env::remove_var(crate::LANG);
688        let lang_result = crate::get_lang();
689
690        assert!(lang_result.is_err());
691    }
692
693    #[test]
694    fn get_user_valid() {
695        std::env::set_var(crate::USER, "vcap");
696        let user_result = crate::get_user();
697
698        assert!(user_result.is_ok());
699        assert_eq!(user_result.unwrap(), "vcap".to_string());
700    }
701
702    #[test]
703    fn get_user_invalid_not_defined() {
704        std::env::remove_var(crate::USER);
705        let user_result = crate::get_user();
706
707        assert!(user_result.is_err());
708    }
709
710    #[test]
711    fn get_memory_limit_invalid_unit() {
712        std::env::set_var("MEMORY_LIMIT", "512K");
713        let memory_limit_result = crate::get_memory_limit();
714
715        assert!(memory_limit_result.is_err());
716    }
717
718    #[test]
719    fn get_memory_limit_invalid_size() {
720        std::env::set_var("MEMORY_LIMIT", "-512M");
721        let memory_limit_result = crate::get_memory_limit();
722
723        assert!(memory_limit_result.is_err());
724    }
725
726    #[test]
727    fn get_memory_limit_invalid_not_defined() {
728        std::env::remove_var(crate::MEMORY_LIMIT);
729        let memory_limit_result = crate::get_memory_limit();
730
731        assert!(memory_limit_result.is_err());
732    }
733
734    #[test]
735    fn get_memory_limit_valid() {
736        std::env::set_var("MEMORY_LIMIT", "512M");
737        let memory_limit_result = crate::get_memory_limit();
738
739        assert!(memory_limit_result.is_ok());
740        assert_eq!(
741            memory_limit_result.unwrap(),
742            crate::MemoryLimit {
743                unit: crate::ByteUnit::Megabyte,
744                size: 512,
745            }
746        )
747    }
748
749    #[test]
750    fn get_app_info_valid() {
751        std::env::set_var("VCAP_APPLICATION", APP_DATA);
752        let app_info_result = crate::get_application_info();
753
754        assert!(app_info_result.is_ok());
755        assert_eq!(
756            app_info_result.unwrap(),
757            serde_json::from_str::<crate::Application>(APP_DATA).unwrap()
758        );
759    }
760
761    #[test]
762    fn get_app_info_invalid() {
763        let mut data = APP_DATA.to_string();
764        data.pop();
765        std::env::set_var("VCAP_APPLICATION", data);
766        let app_info_result = crate::get_application_info();
767
768        assert!(app_info_result.is_err());
769    }
770
771    #[test]
772    fn get_app_info_invalid_not_set() {
773        std::env::remove_var("VCAP_APPLICATION");
774        let app_info_result = crate::get_application_info();
775
776        assert!(app_info_result.is_err());
777    }
778
779    #[test]
780    fn get_services_valid() {
781        use std::collections::HashMap;
782        std::env::set_var("VCAP_SERVICES", SERVICE_DATA);
783        let service_info = crate::get_services();
784
785        assert!(service_info.is_ok());
786        assert_eq!(
787            service_info.unwrap(),
788            serde_json::from_str::<HashMap<String, Vec<crate::Service>>>(SERVICE_DATA).unwrap()
789        );
790    }
791
792    #[test]
793    fn get_services_invalid_not_set() {
794        std::env::remove_var("VCAP_SERVICES");
795        let service_info = crate::get_services();
796
797        assert!(service_info.is_err());
798    }
799
800    #[test]
801    fn get_services_invalid_mal_formed() {
802        let mut data = SERVICE_DATA.to_string();
803        data.pop();
804
805        std::env::set_var("VCAP_SERVICES", data);
806
807        let service_info = crate::get_services();
808
809        assert!(service_info.is_err());
810    }
811
812    #[test]
813    fn get_services_by_name_valid() {
814        std::env::set_var("VCAP_SERVICES", SERVICE_DATA);
815
816        #[derive(serde::Serialize, serde::Deserialize)]
817        struct DbCredentials {
818            host: String,
819            port: String,
820            database: String,
821            username: String,
822            password: String,
823            database_uri: String,
824            uri: String,
825            replica_set: String,
826        }
827        let service_info = crate::get_service_by_name::<DbCredentials>("my-db");
828
829        assert!(service_info.is_ok());
830        assert_eq!(service_info.unwrap().name, "my-db");
831    }
832
833    #[test]
834    fn get_services_by_name_invalid_creds_schema() {
835        std::env::set_var("VCAP_SERVICES", SERVICE_DATA);
836
837        #[derive(serde::Serialize, serde::Deserialize)]
838        struct DbCredentials {
839            host: String,
840            port: String,
841            database: String,
842            username: String,
843            password: String,
844            database_uri: String,
845            uri: String,
846            replica_set: String,
847            not_avaiable: String,
848        }
849        let service_info = crate::get_service_by_name::<DbCredentials>("my-db");
850
851        assert!(service_info.is_err());
852    }
853
854    #[test]
855    fn get_services_by_name_invalid() {
856        std::env::set_var("VCAP_SERVICES", SERVICE_DATA);
857
858        let service_info = crate::get_service_by_name::<serde_json::Value>("the-db");
859
860        assert!(service_info.is_err());
861    }
862
863    #[test]
864    fn get_services_by_name_invalid_not_set() {
865        std::env::remove_var("VCAP_SERVICES");
866
867        let service_info = crate::get_service_by_name::<serde_json::Value>("the-db");
868
869        assert!(service_info.is_err());
870    }
871
872    #[test]
873    fn get_services_by_type_valid() {
874        std::env::set_var("VCAP_SERVICES", SERVICE_DATA);
875
876        #[derive(serde::Serialize, serde::Deserialize, Debug)]
877        struct DbCredentials {
878            pub host: String,
879            pub port: String,
880            pub database: String,
881            pub username: String,
882            pub password: String,
883            pub database_uri: String,
884            pub uri: String,
885            pub replica_set: String,
886        }
887        let service_info = crate::get_services_by_type::<DbCredentials>("mongodb");
888
889        assert!(service_info.is_ok());
890
891        let data = service_info.unwrap();
892        let data: &crate::Service<DbCredentials> = data.first().unwrap();
893
894        assert_eq!(data.name, "my-db");
895        assert_eq!(data.label, "mongodb");
896    }
897
898    #[test]
899    fn get_services_by_type_invalid_creds_schema() {
900        std::env::set_var("VCAP_SERVICES", SERVICE_DATA);
901
902        #[derive(serde::Serialize, serde::Deserialize, Debug)]
903        struct DbCredentials {
904            pub host: String,
905            pub port: String,
906            pub database: String,
907            pub username: String,
908            pub password: String,
909            pub database_uri: String,
910            pub uri: String,
911            pub replica_set: String,
912            pub not_avaiable: String,
913        }
914        let service_info = crate::get_services_by_type::<DbCredentials>("mongodb");
915
916        assert!(service_info.is_err());
917    }
918
919    #[test]
920    fn get_services_by_type_invalid() {
921        std::env::set_var("VCAP_SERVICES", SERVICE_DATA);
922
923        let service_info = crate::get_services_by_type::<serde_json::Value>("some-type");
924
925        assert!(service_info.is_err());
926    }
927
928    #[test]
929    fn get_services_by_type_invalid_not_set() {
930        std::env::remove_var("VCAP_SERVICES");
931
932        let service_info = crate::get_services_by_type::<serde_json::Value>("some-type");
933
934        assert!(service_info.is_err());
935    }
936
937    #[test]
938    fn get_database_url_valid() {
939        std::env::set_var("DATABASE_URL", "mysql://root:root@192.168.2.3:3098");
940        let database_url_result = crate::get_database_url();
941
942        assert!(database_url_result.is_ok());
943        assert_eq!(
944            database_url_result.unwrap().to_string(),
945            "mysql://root:root@192.168.2.3:3098/".to_string()
946        );
947    }
948
949    #[test]
950    fn get_database_url_invalid() {
951        std::env::set_var("DATABASE_URL", "mysql:/root@root@192.168.2.3:3098");
952        let database_url_result = crate::get_database_url();
953
954        assert!(database_url_result.is_err());
955    }
956
957    #[test]
958    fn get_database_url_invalid_not_set() {
959        std::env::remove_var(crate::DATABASE_URL);
960        let database_url_result = crate::get_database_url();
961
962        assert!(database_url_result.is_err());
963    }
964
965    #[test]
966    fn get_home_valid() {
967        std::env::set_var("HOME", "/home/vcap");
968        let home_result = crate::get_home();
969
970        assert!(home_result.is_ok());
971        assert_eq!(home_result.unwrap().to_str().unwrap(), "/home/vcap");
972    }
973
974    #[test]
975    fn get_home_not_set() {
976        std::env::remove_var("HOME");
977        let home_result = crate::get_home();
978
979        assert!(home_result.is_err());
980    }
981
982    #[test]
983    fn get_pwd_valid() {
984        std::env::set_var("PWD", "/home/vcap");
985        let pwd_result = crate::get_pwd();
986
987        assert!(pwd_result.is_ok());
988        assert_eq!(pwd_result.unwrap().to_str().unwrap(), "/home/vcap");
989    }
990
991    #[test]
992    fn get_pwd_not_set() {
993        std::env::remove_var("PWD");
994        let pwd_result = crate::get_pwd();
995
996        assert!(pwd_result.is_err());
997    }
998
999    #[test]
1000    fn get_tmp_dir_valid() {
1001        std::env::set_var("TMPDIR", "/tmp");
1002        let tmp_dir_result = crate::get_tmp_dir();
1003
1004        assert!(tmp_dir_result.is_ok());
1005        assert_eq!(tmp_dir_result.unwrap().to_str().unwrap(), "/tmp");
1006    }
1007
1008    #[test]
1009    fn get_tmp_dir_not_set() {
1010        std::env::remove_var("TMPDIR");
1011        let tmp_dir_result = crate::get_tmp_dir();
1012
1013        assert!(tmp_dir_result.is_err());
1014    }
1015
1016    #[test]
1017    fn is_cf_env_valid() {
1018        std::env::set_var("VCAP_APPLICATION", "test");
1019        let cf_env_result = crate::is_cf_env();
1020
1021        assert!(cf_env_result);
1022    }
1023
1024    #[test]
1025    fn is_cf_env_invalid() {
1026        std::env::remove_var("VCAP_APPLICATION");
1027        let cf_env_result = crate::is_cf_env();
1028
1029        assert!(!cf_env_result);
1030    }
1031}