1extern crate regex;
152
153pub mod resource;
154pub mod http;
155
156use std::thread;
157use std::net::TcpListener;
158use std::net::TcpStream;
159use std::io::prelude::*;
160use std::io::Error;
161use std::io::BufReader;
162use std::sync::Arc;
163use std::sync::Mutex;
164use std::sync::mpsc;
165use std::collections::HashMap;
166use http::Method;
167use http::Status;
168pub use resource::Resource;
169
170type ServerResources = Arc<Mutex<Vec<Resource>>>;
171type RequestsTX = Arc<Mutex<Option<mpsc::Sender<Request>>>>;
172
173pub struct TestServer {
175 port: u16,
176 resources: ServerResources,
177 requests_tx: RequestsTX
178}
179
180impl TestServer {
181 pub fn new() -> Result<TestServer, Error> {
193 TestServer::new_with_port(0)
194 }
195
196 pub fn new_with_port(port: u16) -> Result<TestServer, Error> {
204 let listener = TcpListener::bind(format!("127.0.0.1:{}", port)).unwrap();
205 let port = listener.local_addr()?.port();
206 let resources: ServerResources = Arc::new(Mutex::new(vec!()));
207 let requests_tx = Arc::new(Mutex::new(None));
208
209 let res = Arc::clone(&resources);
210 let tx = Arc::clone(&requests_tx);
211
212 thread::spawn(move || {
213 for stream in listener.incoming() {
214 let stream = stream.unwrap();
215
216 let mut buffer = [0; 512];
217 stream.peek(&mut buffer).unwrap();
218
219 if buffer.starts_with(b"CLOSE") {
220 break;
221 }
222
223 handle_connection(&stream, res.clone(), tx.clone());
224 }
225 });
226
227 Ok(TestServer{ port, resources, requests_tx })
228 }
229
230 pub fn port(&self) -> u16 {
239 self.port
240 }
241
242 pub fn close(&self) {
255 if let Ok(mut stream) = TcpStream::connect(format!("127.0.0.1:{}", self.port)) {
256 stream.write_all(b"CLOSE").unwrap();
257 stream.flush().unwrap();
258 }
259 }
260
261 pub fn create_resource(&self, uri: &str) -> Resource {
273 let mut resources = self.resources.lock().unwrap();
274 let resource = Resource::new(uri);
275
276 resources.push(resource.clone());
277
278 resource
279 }
280
281 pub fn requests(&self) -> mpsc::Receiver<Request> {
296 let (tx, rx) = mpsc::channel();
297
298 *self.requests_tx.lock().unwrap() = Some(tx);
299
300 rx
301 }
302}
303
304impl Drop for TestServer {
305 fn drop(&mut self) {
306 self.close();
307 }
308}
309
310fn handle_connection(stream: &TcpStream, resources: ServerResources, requests_tx: RequestsTX) {
311 let stream = stream.try_clone().unwrap();
312
313 thread::spawn(move || {
314 let mut write_stream = stream.try_clone().unwrap();
315 let mut reader = BufReader::new(stream);
316
317 let (method, url) = parse_request_header(&mut reader);
318 let resource = find_resource(method.clone(), url.clone(), resources);
319
320 if let Some(delay) = resource.get_delay() {
321 thread::sleep(delay);
322 }
323
324 write_stream.write_all(resource.build_response(&url).as_bytes()).unwrap();
325 write_stream.flush().unwrap();
326
327 if let Some(ref tx) = *requests_tx.lock().unwrap() {
328 let mut headers = HashMap::new();
329
330 for line in reader.lines() {
331 let line = line.unwrap();
332
333 if line == "" {
334 break
335 }
336
337 let (name, value) = parse_header(line);
338 headers.insert(name, value);
339 }
340
341 tx.send(Request { url, method, headers }).unwrap();
342 }
343
344 if resource.is_stream() {
345 let receiver = resource.stream_receiver();
346 for line in receiver.iter() {
347 write_stream.write_all(line.as_bytes()).unwrap();
348 write_stream.flush().unwrap();
349 }
350 }
351
352 });
353}
354
355fn parse_header(message: String) -> (String, String) {
356 let parts: Vec<&str> = message.splitn(2, ':').collect();
357 (String::from(parts[0]), String::from(parts[1].trim()))
358}
359
360fn parse_request_header(reader: &mut dyn BufRead) -> (String, String) {
361 let mut request_header = String::from("");
362 reader.read_line(&mut request_header).unwrap();
363
364 let request_header: Vec<&str> = request_header
365 .split_whitespace().collect();
366
367 (request_header[0].to_string(), request_header[1].to_string())
368}
369
370fn find_resource(method: String, url: String, resources: ServerResources) -> Resource {
371 let resources = resources.lock().unwrap();
372
373 match resources.iter().find(|r| r.matches_uri(&url) && r.get_method().equal(&method) ) {
374 Some(resource) => {
375 resource.increment_request_count();
376 resource.clone()
377 },
378 None => {
379 let resources_for_uri = resources.iter().filter(|r| r.matches_uri(&url));
381 if resources_for_uri.count() == 0 {
382 return Resource::new(&url).status(Status::NotFound).clone();
383 }
384 Resource::new(&url).status(Status::MethodNotAllowed).clone()
385 }
386 }
387}
388
389
390#[derive(Debug, PartialEq)]
394pub struct Request {
395 pub url: String,
397 pub method: String,
399 pub headers: HashMap<String, String>
401}
402
403#[cfg(test)]
404mod tests {
405 use std::io::prelude::*;
406 use std::io::BufReader;
407 use std::io::ErrorKind;
408 use std::net::TcpStream;
409 use std::time::Duration;
410 use std::sync::mpsc;
411 use super::*;
412
413 fn make_request(port: u16, uri: &str) -> TcpStream {
414 request(port, uri, "GET")
415 }
416
417 fn make_post_request(port: u16, uri: &str) -> TcpStream {
418 request(port, uri, "POST")
419 }
420
421 fn request(port: u16, uri: &str, method: &str) -> TcpStream {
422 let host = format!("127.0.0.1:{}", port);
423 let mut stream = TcpStream::connect(host).unwrap();
424 let request = format!(
425 "{} {} HTTP/1.1\r\nContent-Type: text\r\n\r\n",
426 method,
427 uri
428 );
429
430 stream.write(request.as_bytes()).unwrap();
431 stream.flush().unwrap();
432
433 stream
434 }
435
436 #[test]
437 fn returns_404_when_requested_enexistent_resource() {
438 let server = TestServer::new().unwrap();
439 let stream = make_request(server.port(), "/something");
440
441 let mut reader = BufReader::new(stream);
442 let mut line = String::new();
443 reader.read_line(&mut line).unwrap();
444
445 assert_eq!(line, "HTTP/1.1 404 Not Found\r\n");
446 }
447
448 #[test]
449 fn server_should_use_random_port() {
450 let server = TestServer::new().unwrap();
451 let server_2 = TestServer::new().unwrap();
452
453 assert_ne!(server.port(), server_2.port());
454 }
455
456 #[test]
457 fn should_close_connection() {
458 let server = TestServer::new().unwrap();
459 server.close();
460
461 thread::sleep(Duration::from_millis(200));
462
463 let host = format!("127.0.0.1:{}", server.port());
464 let stream = TcpStream::connect(host);
465
466 assert!(stream.is_err());
467 if let Err(e) = stream {
468 assert_eq!(e.kind(), ErrorKind::ConnectionRefused);
469 }
470 }
471
472 #[test]
473 fn should_handle_multiple_resources() {
474 let server = TestServer::new().unwrap();
475 let resource = server.create_resource("/this");
476 resource.status(Status::OK).body("<this body>");
477 thread::sleep(Duration::from_millis(200));
478 let resource2 = server.create_resource("/that");
479 resource2.status(Status::OK).body("<that body>");
480
481 assert_eq!(resource.request_count(), 0);
482 assert_eq!(resource2.request_count(), 0);
483
484 let _ = make_request(server.port(), "/this");
485
486 thread::sleep(Duration::from_millis(200));
487 let _ = make_request(server.port(), "/that");
488 thread::sleep(Duration::from_millis(200));
489
490 assert_eq!(resource.request_count(), 1);
491 assert_eq!(resource2.request_count(), 1);
492 }
493
494 #[test]
495 fn should_create_resource() {
496 let server = TestServer::new().unwrap();
497 server.create_resource("/something");
498
499 let stream = make_request(server.port(), "/something");
500
501 let mut reader = BufReader::new(stream);
502 let mut line = String::new();
503 reader.read_line(&mut line).unwrap();
504
505 assert_eq!(line, "HTTP/1.1 200 Ok\r\n");
506 }
507
508 #[test]
509 fn should_return_configured_status_for_resource_resource() {
510 let server = TestServer::new().unwrap();
511 let resource = server.create_resource("/something-else");
512
513 resource.status(Status::OK);
514
515 let stream = make_request(server.port(), "/something-else");
516
517 let mut reader = BufReader::new(stream);
518 let mut line = String::new();
519 reader.read_line(&mut line).unwrap();
520
521 assert_eq!(line, "HTTP/1.1 200 Ok\r\n");
522 }
523
524 #[test]
525 fn should_return_resource_body() {
526 let server = TestServer::new().unwrap();
527 let resource = server.create_resource("/something-else");
528
529 resource.status(Status::OK).body("<some body>");
530
531 let stream = make_request(server.port(), "/something-else");
532
533 let mut reader = BufReader::new(stream);
534 let mut line = String::new();
535 reader.read_to_string(&mut line).unwrap();
536
537 assert_eq!(line, "HTTP/1.1 200 Ok\r\n\r\n<some body>");
538 }
539
540 #[test]
541 fn should_return_resource_body_with_params() {
542 let server = TestServer::new().unwrap();
543 let resource = server.create_resource("/user/{userId}/{thing_id}/{yepyep}");
544
545 resource.status(Status::OK).body("User: {path.userId} Thing: {path.thing_id} Sth: {path.yepyep}");
546
547 let stream = make_request(server.port(), "/user/123/abc/Hello!");
548
549 let mut reader = BufReader::new(stream);
550 let mut line = String::new();
551 reader.read_to_string(&mut line).unwrap();
552
553 assert_eq!(line, "HTTP/1.1 200 Ok\r\n\r\nUser: 123 Thing: abc Sth: Hello!");
554 }
555
556 #[test]
557 fn should_work_with_regex_uri() {
558 let server = TestServer::new().unwrap();
559 let resource = server.create_resource("/hello/[0-9]/[A-z]/.*");
560
561 resource.method(Method::POST).status(Status::OK).body("<some body>");
562
563 let stream = make_post_request(server.port(), "/hello/8/b/doesntmatter-hehe");
564
565 let mut reader = BufReader::new(stream);
566 let mut line = String::new();
567 reader.read_to_string(&mut line).unwrap();
568
569 assert_eq!(line, "HTTP/1.1 200 Ok\r\n\r\n<some body>");
570 }
571
572
573 #[test]
574 fn should_listen_to_defined_method() {
575 let server = TestServer::new().unwrap();
576 let resource = server.create_resource("/something-else");
577
578 resource.method(Method::POST).status(Status::OK).body("<some body>");
579
580 let stream = make_post_request(server.port(), "/something-else");
581
582 let mut reader = BufReader::new(stream);
583 let mut line = String::new();
584 reader.read_to_string(&mut line).unwrap();
585
586 assert_eq!(line, "HTTP/1.1 200 Ok\r\n\r\n<some body>");
587 }
588
589 #[test]
590 fn should_allow_multiple_methods_for_same_uri() {
591 let server = TestServer::new().unwrap();
592 let resource = server.create_resource("/something-else");
593 let resource2 = server.create_resource("/something-else");
594
595 resource.method(Method::GET).status(Status::OK).body("<some body GET>");
596 resource2.method(Method::POST).status(Status::OK).body("<some body POST>");
597
598 let stream_get = make_request(server.port(), "/something-else");
599 let stream_post = make_post_request(server.port(), "/something-else");
600
601 let mut reader = BufReader::new(stream_get);
602 let mut line = String::new();
603 reader.read_to_string(&mut line).unwrap();
604
605 let mut reader = BufReader::new(stream_post);
606 let mut line2 = String::new();
607 reader.read_to_string(&mut line2).unwrap();
608
609 assert_eq!(line, "HTTP/1.1 200 Ok\r\n\r\n<some body GET>");
610 assert_eq!(line2, "HTTP/1.1 200 Ok\r\n\r\n<some body POST>");
611 }
612
613 #[test]
614 fn should_return_405_when_method_not_defined() {
615 let server = TestServer::new().unwrap();
616 let resource = server.create_resource("/something-else");
617
618 resource.method(Method::POST).status(Status::OK).body("<some body>");
619
620 let stream = make_request(server.port(), "/something-else");
621
622 let mut reader = BufReader::new(stream);
623 let mut line = String::new();
624 reader.read_to_string(&mut line).unwrap();
625
626 assert_eq!(line, "HTTP/1.1 405 Method Not Allowed\r\n\r\n");
627 }
628
629 #[test]
630 fn should_increment_request_count() {
631 let server = TestServer::new().unwrap();
632 let resource = server.create_resource("/something-else");
633
634 resource.status(Status::OK).body("<some body>");
635
636 assert_eq!(resource.request_count(), 0);
637
638 let _ = make_request(server.port(), "/something-else");
639 let _ = make_request(server.port(), "/something-else");
640
641 thread::sleep(Duration::from_millis(200));
642
643 assert_eq!(resource.request_count(), 2);
644
645 }
646
647 #[test]
648 fn should_expose_stream() {
649 let server = TestServer::new().unwrap();
650 let resource = server.create_resource("/something-else");
651 resource.stream();
652
653 let (tx, rx) = mpsc::channel();
654
655 let port = server.port();
656
657 thread::spawn(move || {
658 let stream = make_request(port, "/something-else");
659 let reader = BufReader::new(stream);
660
661 for line in reader.lines() {
662 let line = line.unwrap();
663 tx.send(line).unwrap();
664 }
665 });
666
667 thread::sleep(Duration::from_millis(200));
668
669 resource.send_line("hello!");
670 resource.send("it's me");
671 resource.send("\n");
672
673 rx.recv().unwrap();
674 rx.recv().unwrap();
675 assert_eq!(rx.recv().unwrap(), "hello!");
676 assert_eq!(rx.recv().unwrap(), "it's me");
677 }
678
679 #[test]
680 fn should_close_client_connections() {
681 let server = TestServer::new().unwrap();
682 let resource = server.create_resource("/something-else");
683 let (tx, rx) = mpsc::channel();
684 let port = server.port();
685
686 resource.stream();
687
688 thread::spawn(move || {
689 let stream = make_request(port, "/something-else");
690 let reader = BufReader::new(stream);
691
692 for _line in reader.lines() {}
693
694 tx.send("connection closed").unwrap();
695 thread::sleep(Duration::from_millis(200));
696 });
697
698 thread::sleep(Duration::from_millis(100));
699 resource.close_open_connections();
700
701 assert_eq!(rx.recv().unwrap(), "connection closed");
702 }
703
704 #[test]
705 fn should_return_requests_metadata() {
706 let server = TestServer::new().unwrap();
707 let (tx, rx) = mpsc::channel();
708 let port = server.port();
709
710 thread::spawn(move || {
711 for req in server.requests().iter() {
712 tx.send(req).unwrap();
713 thread::sleep(Duration::from_millis(400));
714 break;
715 }
716 });
717
718 thread::sleep(Duration::from_millis(100));
719 let _req = make_request(port, "/something-else");
720
721 let mut request_headers = HashMap::new();
722 request_headers.insert(String::from("Content-Type"), String::from("text"));
723
724 let expected_request = Request {
725 url: String::from("/something-else"),
726 method: String::from("GET"),
727 headers: request_headers
728 };
729
730 assert_eq!(rx.recv().unwrap(), expected_request);
731 }
732
733 #[test]
734 fn should_delay_response() {
735 let server = TestServer::new().unwrap();
736 let resource = server.create_resource("/something-else");
737 resource.delay(Duration::from_millis(300));
738
739 let (tx, rx) = mpsc::channel();
740
741 let port = server.port();
742
743 thread::spawn(move || {
744 let stream = make_request(port, "/something-else");
745 let reader = BufReader::new(stream);
746
747 for line in reader.lines() {
748 let line = line.unwrap();
749 tx.send(line).unwrap();
750 }
751 });
752
753 thread::sleep(Duration::from_millis(200));
754
755 assert!(rx.try_recv().is_err());
756 thread::sleep(Duration::from_millis(200));
757 assert_eq!(rx.try_recv().unwrap(), "HTTP/1.1 200 Ok");
758 }
759
760 #[test]
761 fn server_should_close_connection_when_dropped() {
762 let port;
763 {
764 let server = TestServer::new().unwrap();
765 port = server.port();
766 thread::sleep(Duration::from_millis(200));
767 }
768
769 let host = format!("localhost:{}", port);
770 let stream = TcpStream::connect(host);
771
772 if let Err(e) = stream {
773 assert_eq!(e.kind(), ErrorKind::ConnectionRefused);
774 } else {
775 panic!("connection should be closed");
776 }
777 }
778}