use webhdfs::{*, sync_client::*, config::HttpsConfig};
use std::time::Duration;
use std::fs::{File, read};
use std::path::Path;
use std::io::{Read, Write, Seek, SeekFrom};
use std::convert::TryInto;
#[test]
fn webhdfs_test() {
println!("Integration test -- start");
let _ = env_logger::builder().is_test(true).try_init();
fn file_as_string(path: &str) -> String {
String::from_utf8_lossy(&read(path).expect("cannot file-as-stirng")).to_owned().to_string()
}
fn file_as_string_opt(path: &str) -> Option<String> {
read(path).map(|s| String::from_utf8_lossy(&s).to_owned().to_string()).ok()
}
let entrypoint = file_as_string("./test-data/entrypoint");
let alt_entrypoint = file_as_string_opt("./test-data/alt-entrypoint");
let has_alt_entrypoint = alt_entrypoint.is_some();
let natmap = crate::config::read_kv_file("./test-data/natmap").expect("cannot read natmap");
let user = file_as_string_opt("./test-data/user");
let dtoken = file_as_string_opt("./test-data/dtoken");
let scheme = file_as_string("./test-data/scheme");
println!("
entrypoint='{e}'
alt_entrypoint='{ae:?}'
natmap={n:?}
user={u:?}
dtoken={d:?}",
e=entrypoint, ae=alt_entrypoint, n=natmap, u=user, d=dtoken);
let nm = NatMap::new(natmap.into_iter()).expect("cannot build natmap");
let mut https_config = HttpsConfig::new();
https_config.danger_accept_invalid_certs = Some(true);
https_config.danger_accept_invalid_hostnames = Some(true);
let entrypoint_uri = format!("{}://{}", scheme, entrypoint);
let b = SyncHdfsClientBuilder::new(entrypoint_uri.parse().expect("Cannot parse entrypoint"))
.default_timeout(Duration::from_secs(180))
.natmap(nm)
.https_settings(https_config.into());
let b = if let Some(w) = alt_entrypoint {
let alt_entrypoint_uri = format!("{}://{}", scheme, w);
b.alt_entrypoint(alt_entrypoint_uri.parse().expect("Cannot parse alt_entrypoint"))
} else { b };
let b = if let Some(w) = dtoken { b.delegation_token(w) } else { b };
let b = if let Some(w) = user { b.user_name(w) } else { b };
let mut cx = b.build().expect("cannot HdfsContext::new");
let readscript = file_as_string("./test-data/readscript");
let writescript = file_as_string("./test-data/writescript");
let source = file_as_string("./test-data/source");
let target = file_as_string("./test-data/target");
let size = file_as_string("./test-data/size").parse::<i64>().unwrap();
let dirsource = file_as_string_opt("./test-data/dirsource");
println!("
source='{s}'
readscript='{r}'
target='{t}'
writescript='{w}'
size={z}",
s=source, r=readscript, t=target, w=writescript, z=size);
let (source_dir, source_sfn) = source.split_at(source.rfind('/').expect("source does not contain '/'"));
let (_, source_fn) = source_sfn.split_at(1);
println!("Test dir and stat");
let dir_resp = cx.dir(source_dir);
println!("Dir: {:?}", dir_resp);
dir_resp.unwrap().file_statuses.file_status.into_iter().find(|fs| fs.path_suffix == source_fn)
.ok_or("cannot find sourcefile in hdfs")
.unwrap();
if let Some(dirsource_dir) = dirsource {
let dir_resp = cx.dir(&dirsource_dir);
println!("Dir: {:?}", dir_resp);
let _ = dir_resp.unwrap();
}
let stat_resp = cx.stat(&source);
println!("Stat: {:?}", stat_resp);
assert_eq!(size, stat_resp.unwrap().file_status.length);
println!("Read test");
#[derive(Debug)]
enum Op {
Seek(i64),
Read(i64, String)
}
fn parse_size(s: &str) -> i64 {
if s.ends_with("k") {
&s[0..s.len()-1].parse::<i64>().unwrap() * 1024
} else if s.ends_with("m") {
&s[0..s.len()-1].parse::<i64>().unwrap() * 1024 * 1024
} else {
s.parse().unwrap()
}
}
let p = readscript.split(' ').filter(|e| !e.is_empty()).map(|s|{
let mut i = s.split(':');
let optype = i.next().unwrap();
let arg = parse_size(i.next().unwrap());
match optype {
"s" => Op::Seek(arg),
"r" => Op::Read(arg, i.next().unwrap().to_owned()),
_ => panic!("invalid optype '{}'", s)
}
}).collect::<Vec<Op>>();
let master_buffer_size = p.iter().map(|w| if let Op::Read(len, _) = w { *len } else { 0 }).max().unwrap().try_into().unwrap();
print!("alloc_mb(len={})...", master_buffer_size);
let mut b = Vec::with_capacity(master_buffer_size);
b.resize(master_buffer_size, 0);
println!("done");
let mut file = ReadHdfsFile::open(cx, source.clone()).unwrap();
for op in p {
println!("{:?}...", op);
match op {
Op::Seek(o) => {
file.seek(SeekFrom::Start(o.try_into().unwrap())).unwrap();
}
Op::Read(l, f) => {
let length: usize = l.try_into().unwrap();
let readcount = file.read(&mut b[0..length]).unwrap();
assert_eq!(length, readcount);
let writecount = File::create(&Path::new(&f)).unwrap().write(&b[0..length]).unwrap();
assert_eq!(length, writecount);
}
}
}
let (cx,_,_) = file.into_parts();
println!("Write test");
let files = writescript.split(' ').filter(|e| !e.is_empty()).collect::<Vec<&str>>();
let mut file = WriteHdfsFile::create(cx, target.clone(), CreateOptions::new(), AppendOptions::new()).unwrap();
let mut count = 0usize;
for file_name in files {
println!("{}", file_name);
let fb = read(Path::new(&file_name)).expect("couldn't read wseg");
count += file.write(&fb).unwrap();
}
assert_eq!(count, size as usize);
let (mut cx,_) = file.into_parts();
let dir_to_make = file_as_string("./test-data/dir-to-make");
cx.mkdirs(&dir_to_make, MkdirsOptions::new()).expect("mkdirs");
let mkdirs_stat_resp = cx.stat(&dir_to_make);
assert_eq!(dirent_type::DIRECTORY, mkdirs_stat_resp.unwrap().file_status.type_);
let dir_to_remove= file_as_string("./test-data/dir-to-remove");
let rmdir_stat_resp = cx.stat(&dir_to_remove);
assert_eq!(dirent_type::DIRECTORY, rmdir_stat_resp.unwrap().file_status.type_);
cx.delete(&dir_to_remove, DeleteOptions::new()).expect("delete (dir)");
let x = cx.stat(&dir_to_remove).expect_err("delete(dir) failed");
println!("{}", x);
if has_alt_entrypoint {
println!("Failover test");
let standby_state = cx.fostate().next();
let mut cx = cx.with_fostate(standby_state);
let dir_resp = cx.dir(source_dir);
println!("Dir: {:?}", dir_resp);
dir_resp.unwrap().file_statuses.file_status.into_iter().find(|fs| fs.path_suffix == source_fn)
.ok_or("cannot find sourcefile in hdfs")
.unwrap();
let dir_resp = cx.dir(source_dir);
println!("Dir(2): {:?}", dir_resp);
dir_resp.unwrap().file_statuses.file_status.into_iter().find(|fs| fs.path_suffix == source_fn)
.ok_or("cannot find sourcefile in hdfs")
.unwrap();
let cx = cx.with_fostate(standby_state);
let mut file = ReadHdfsFile::open(cx, source.clone()).unwrap();
let mut b = Vec::with_capacity(1024);
b.resize(b.capacity(), 0);
file.read(&mut b).unwrap();
} else {
println!("No alt_entrypoint specified -- skip failover test");
}
}