]> git.lizzy.rs Git - rust.git/blob - src/libstd/io/test.rs
auto merge of #16225 : pczarn/rust/iter-refactoring, r=kballard
[rust.git] / src / libstd / io / test.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /*! Various utility functions useful for writing I/O tests */
12
13 #![macro_escape]
14
15 use libc;
16 use os;
17 use prelude::*;
18 use std::io::net::ip::*;
19 use sync::atomic::{AtomicUint, INIT_ATOMIC_UINT, Relaxed};
20
21 macro_rules! iotest (
22     { fn $name:ident() $b:block $(#[$a:meta])* } => (
23         mod $name {
24             #![allow(unused_imports)]
25
26             use super::super::*;
27             use super::*;
28             use io;
29             use prelude::*;
30             use io::*;
31             use io::fs::*;
32             use io::test::*;
33             use io::net::tcp::*;
34             use io::net::ip::*;
35             use io::net::udp::*;
36             #[cfg(unix)]
37             use io::net::unix::*;
38             use io::timer::*;
39             use io::process::*;
40             use rt::running_on_valgrind;
41             use str;
42
43             fn f() $b
44
45             $(#[$a])* #[test] fn green() { f() }
46             $(#[$a])* #[test] fn native() {
47                 use native;
48                 let (tx, rx) = channel();
49                 native::task::spawn(proc() { tx.send(f()) });
50                 rx.recv();
51             }
52         }
53     )
54 )
55
56 /// Get a port number, starting at 9600, for use in tests
57 pub fn next_test_port() -> u16 {
58     static mut next_offset: AtomicUint = INIT_ATOMIC_UINT;
59     unsafe {
60         base_port() + next_offset.fetch_add(1, Relaxed) as u16
61     }
62 }
63
64 /// Get a temporary path which could be the location of a unix socket
65 pub fn next_test_unix() -> Path {
66     static mut COUNT: AtomicUint = INIT_ATOMIC_UINT;
67     // base port and pid are an attempt to be unique between multiple
68     // test-runners of different configurations running on one
69     // buildbot, the count is to be unique within this executable.
70     let string = format!("rust-test-unix-path-{}-{}-{}",
71                          base_port(),
72                          unsafe {libc::getpid()},
73                          unsafe {COUNT.fetch_add(1, Relaxed)});
74     if cfg!(unix) {
75         os::tmpdir().join(string)
76     } else {
77         Path::new(format!("{}{}", r"\\.\pipe\", string))
78     }
79 }
80
81 /// Get a unique IPv4 localhost:port pair starting at 9600
82 pub fn next_test_ip4() -> SocketAddr {
83     SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: next_test_port() }
84 }
85
86 /// Get a unique IPv6 localhost:port pair starting at 9600
87 pub fn next_test_ip6() -> SocketAddr {
88     SocketAddr { ip: Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1), port: next_test_port() }
89 }
90
91 /*
92 XXX: Welcome to MegaHack City.
93
94 The bots run multiple builds at the same time, and these builds
95 all want to use ports. This function figures out which workspace
96 it is running in and assigns a port range based on it.
97 */
98 fn base_port() -> u16 {
99
100     let base = 9600u16;
101     let range = 1000u16;
102
103     let bases = [
104         ("32-opt", base + range * 1),
105         ("32-nopt", base + range * 2),
106         ("64-opt", base + range * 3),
107         ("64-nopt", base + range * 4),
108         ("64-opt-vg", base + range * 5),
109         ("all-opt", base + range * 6),
110         ("snap3", base + range * 7),
111         ("dist", base + range * 8)
112     ];
113
114     // FIXME (#9639): This needs to handle non-utf8 paths
115     let path = os::getcwd();
116     let path_s = path.as_str().unwrap();
117
118     let mut final_base = base;
119
120     for &(dir, base) in bases.iter() {
121         if path_s.contains(dir) {
122             final_base = base;
123             break;
124         }
125     }
126
127     return final_base;
128 }
129
130 /// Raises the file descriptor limit when running tests if necessary
131 pub fn raise_fd_limit() {
132     unsafe { darwin_fd_limit::raise_fd_limit() }
133 }
134
135 #[cfg(target_os="macos")]
136 #[allow(non_camel_case_types)]
137 mod darwin_fd_limit {
138     /*!
139      * darwin_fd_limit exists to work around an issue where launchctl on Mac OS X defaults the
140      * rlimit maxfiles to 256/unlimited. The default soft limit of 256 ends up being far too low
141      * for our multithreaded scheduler testing, depending on the number of cores available.
142      *
143      * This fixes issue #7772.
144      */
145
146     use libc;
147     type rlim_t = libc::uint64_t;
148     struct rlimit {
149         rlim_cur: rlim_t,
150         rlim_max: rlim_t
151     }
152     extern {
153         // name probably doesn't need to be mut, but the C function doesn't specify const
154         fn sysctl(name: *mut libc::c_int, namelen: libc::c_uint,
155                   oldp: *mut libc::c_void, oldlenp: *mut libc::size_t,
156                   newp: *mut libc::c_void, newlen: libc::size_t) -> libc::c_int;
157         fn getrlimit(resource: libc::c_int, rlp: *mut rlimit) -> libc::c_int;
158         fn setrlimit(resource: libc::c_int, rlp: *const rlimit) -> libc::c_int;
159     }
160     static CTL_KERN: libc::c_int = 1;
161     static KERN_MAXFILESPERPROC: libc::c_int = 29;
162     static RLIMIT_NOFILE: libc::c_int = 8;
163
164     pub unsafe fn raise_fd_limit() {
165         // The strategy here is to fetch the current resource limits, read the kern.maxfilesperproc
166         // sysctl value, and bump the soft resource limit for maxfiles up to the sysctl value.
167         use ptr::mut_null;
168         use mem::size_of_val;
169         use os::last_os_error;
170
171         // Fetch the kern.maxfilesperproc value
172         let mut mib: [libc::c_int, ..2] = [CTL_KERN, KERN_MAXFILESPERPROC];
173         let mut maxfiles: libc::c_int = 0;
174         let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t;
175         if sysctl(&mut mib[0], 2, &mut maxfiles as *mut libc::c_int as *mut libc::c_void, &mut size,
176                   mut_null(), 0) != 0 {
177             let err = last_os_error();
178             fail!("raise_fd_limit: error calling sysctl: {}", err);
179         }
180
181         // Fetch the current resource limits
182         let mut rlim = rlimit{rlim_cur: 0, rlim_max: 0};
183         if getrlimit(RLIMIT_NOFILE, &mut rlim) != 0 {
184             let err = last_os_error();
185             fail!("raise_fd_limit: error calling getrlimit: {}", err);
186         }
187
188         // Bump the soft limit to the smaller of kern.maxfilesperproc and the hard limit
189         rlim.rlim_cur = ::cmp::min(maxfiles as rlim_t, rlim.rlim_max);
190
191         // Set our newly-increased resource limit
192         if setrlimit(RLIMIT_NOFILE, &rlim) != 0 {
193             let err = last_os_error();
194             fail!("raise_fd_limit: error calling setrlimit: {}", err);
195         }
196     }
197 }
198
199 #[cfg(not(target_os="macos"))]
200 mod darwin_fd_limit {
201     pub unsafe fn raise_fd_limit() {}
202 }