From afa5b57dc7864443c39f1bdd785bdd8cad99e43c Mon Sep 17 00:00:00 2001
From: Makis Maropoulos <makis@ideopod.com>
Date: Tue, 5 Jul 2016 14:29:32 +0200
Subject: [PATCH] Add virtual listen same as NoListen- some changes in order
 the server_test no need any system modification

---
 config/server.go |  2 ++
 http.go          |  5 +++++
 initiatory.go    | 34 +++++++++++-----------------------
 iris.go          | 37 ++++++++++++++++++++++++++++++++-----
 server_test.go   | 20 +++++++++-----------
 5 files changed, 59 insertions(+), 39 deletions(-)

diff --git a/config/server.go b/config/server.go
index b580fce5..089ced10 100644
--- a/config/server.go
+++ b/config/server.go
@@ -37,6 +37,8 @@ type Server struct {
 	//
 	// example: https://github.com/iris-contrib/examples/tree/master/multiserver_listening2
 	RedirectTo string
+	// Virtual If this server is not really listens to a real host, it mostly used in order to achieve testing without system modifications
+	Virtual bool
 }
 
 // DefaultServer returns the default configs for the server
diff --git a/http.go b/http.go
index 6d72aaa5..c3ff9e57 100644
--- a/http.go
+++ b/http.go
@@ -431,10 +431,15 @@ func (s *Server) Open() error {
 		}
 	}
 
+	if s.Config.Virtual {
+		return nil
+	}
+
 	if s.Config.Mode > 0 {
 		return s.listenUNIX()
 	}
 	return s.listen()
+
 }
 
 // Close terminates the server
diff --git a/initiatory.go b/initiatory.go
index ec3f3186..2c6fa358 100644
--- a/initiatory.go
+++ b/initiatory.go
@@ -179,6 +179,7 @@ func (s *Framework) openServer() (err error) {
 	// set the server's handler now, in order to give the chance to the plugins to add their own middlewares and routes to this station
 	s.HTTPServer.SetHandler(s.mux)
 	if err = s.HTTPServer.Open(); err == nil {
+
 		// print the banner
 		if !s.Config.DisableBanner {
 			s.Logger.PrintBanner(banner,
@@ -186,10 +187,16 @@ func (s *Framework) openServer() (err error) {
 					s.HTTPServer.Host()))
 		}
 		s.Plugins.DoPostListen(s)
-		s.Available <- true
-		ch := make(chan os.Signal)
-		<-ch
-		s.Close()
+		go func() {
+			s.Available <- true
+		}()
+
+		if !s.Config.Server.Virtual {
+			ch := make(chan os.Signal)
+			<-ch
+			s.Close()
+		}
+
 	}
 	return
 }
@@ -201,25 +208,6 @@ func (s *Framework) closeServer() error {
 	return s.HTTPServer.Close()
 }
 
-// justServe initializes the whole framework but server doesn't listens to a specific net.Listener
-func (s *Framework) justServe(optionalAddr ...string) *Server {
-	s.HTTPServer.Config = &s.Config.Server
-
-	if len(optionalAddr) > 0 {
-		s.HTTPServer.Config.ListeningAddr = optionalAddr[0]
-	}
-
-	s.initialize()
-	s.Plugins.DoPreListen(s)
-	s.HTTPServer.SetHandler(s.mux)
-	s.Plugins.DoPostListen(s)
-	go func() {
-		s.Available <- true
-	}()
-
-	return s.HTTPServer
-}
-
 // tester returns the test framework
 func (s *Framework) tester(t *testing.T) *httpexpect.Expect {
 	if s.testFramework == nil {
diff --git a/iris.go b/iris.go
index fc1352e2..f4d783c1 100644
--- a/iris.go
+++ b/iris.go
@@ -94,6 +94,7 @@ type (
 		ListenUNIX(string, os.FileMode)
 		SecondaryListen(config.Server) *Server
 		NoListen(...string) *Server
+		ListenVirtual(cfg ...config.Server) *Server
 		Close()
 		// global middleware prepending, registers to all subdomains, to all parties, you can call it at the last also
 		MustUse(...Handler)
@@ -328,9 +329,11 @@ func (s *Framework) SecondaryListen(cfg config.Server) *Server {
 		go func() { // goroutine in order to not block any runtime post listeners
 			srv.Handler = s.HTTPServer.Handler
 			if err := srv.Open(); err == nil {
-				ch := make(chan os.Signal)
-				<-ch
-				srv.Close()
+				if !cfg.Virtual {
+					ch := make(chan os.Signal)
+					<-ch
+					srv.Close()
+				}
 			}
 		}()
 	}))
@@ -346,7 +349,31 @@ func NoListen(optionalAddr ...string) *Server {
 // NoListen is useful only when you want to test Iris, it doesn't starts the server but it configures and returns it
 // initializes the whole framework but server doesn't listens to a specific net.Listener
 func (s *Framework) NoListen(optionalAddr ...string) *Server {
-	return s.justServe(optionalAddr...)
+	if len(optionalAddr) > 0 {
+		s.Config.Server.ListeningAddr = optionalAddr[0]
+	}
+	return s.ListenVirtual()
+}
+
+// ListenVirtual is useful only when you want to test Iris, it doesn't starts the server but it configures and returns it
+// initializes the whole framework but server doesn't listens to a specific net.Listener
+// same as NoListen
+func ListenVirtual(cfg ...config.Server) *Server {
+	return Default.ListenVirtual(cfg...)
+}
+
+// ListenVirtual is useful only when you want to test Iris, it doesn't starts the server but it configures and returns it
+// initializes the whole framework but server doesn't listens to a specific net.Listener
+// same as NoListen
+func (s *Framework) ListenVirtual(cfg ...config.Server) *Server {
+	if len(cfg) > 0 {
+		s.Config.Server = cfg[0]
+	}
+	s.Config.DisableBanner = true
+	s.Config.Server.Virtual = true
+
+	s.Must(s.openServer())
+	return s.HTTPServer
 }
 
 // CloseWithErr terminates the server and returns an error if any
@@ -609,7 +636,7 @@ func (s *Framework) TemplateString(templateFile string, pageContext interface{},
 func NewTester(api *Framework, t *testing.T) *httpexpect.Expect {
 	api.Config.DisableBanner = true
 	if !api.HTTPServer.IsListening() { // maybe the user called this after .Listen/ListenTLS/ListenUNIX, the tester can be used as standalone (with no running iris instance) or inside a running instance/app
-		api.NoListen()
+		api.ListenVirtual()
 		if ok := <-api.Available; !ok {
 			t.Fatal("Unexpected error: server cannot start, please report this as bug!!")
 		}
diff --git a/server_test.go b/server_test.go
index 15720145..e4276769 100644
--- a/server_test.go
+++ b/server_test.go
@@ -15,6 +15,7 @@ Linux:
 */
 
 import (
+	"io/ioutil"
 	"net/http"
 	"os"
 	"testing"
@@ -22,6 +23,7 @@ import (
 
 	"github.com/gavv/httpexpect"
 	"github.com/kataras/iris/config"
+	"github.com/kataras/iris/utils"
 )
 
 const (
@@ -84,12 +86,13 @@ func TestMultiRunningServers(t *testing.T) {
 	host := "mydomain.com:443" // you have to add it to your hosts file( for windows, as 127.0.0.1 mydomain.com)
 
 	// create the key and cert files on the fly, and delete them when this test finished
-	certFile, ferr := os.Create(testCertFilename)
+	certFile, ferr := ioutil.TempFile(utils.AssetsDirectory, "_iris")
+
 	if ferr != nil {
 		t.Fatal(ferr.Error())
 	}
 
-	keyFile, ferr := os.Create(testKeyFilename)
+	keyFile, ferr := ioutil.TempFile(utils.AssetsDirectory, "_iris")
 	if ferr != nil {
 		t.Fatal(ferr.Error())
 	}
@@ -100,11 +103,11 @@ func TestMultiRunningServers(t *testing.T) {
 	defer func() {
 		certFile.Close()
 		time.Sleep(350 * time.Millisecond)
-		os.Remove(testCertFilename)
+		os.Remove(certFile.Name())
 
 		keyFile.Close()
 		time.Sleep(350 * time.Millisecond)
-		os.Remove(testKeyFilename)
+		os.Remove(keyFile.Name())
 	}()
 
 	initDefault()
@@ -114,14 +117,9 @@ func TestMultiRunningServers(t *testing.T) {
 		ctx.Write("Hello from %s", ctx.HostString())
 	})
 
-	secondary := SecondaryListen(config.Server{ListeningAddr: ":80", RedirectTo: "https://" + host}) // start one secondary server
+	secondary := SecondaryListen(config.Server{ListeningAddr: ":80", RedirectTo: "https://" + host, Virtual: true}) // start one secondary server
 	// start the main server
-	go func() {
-		err := ListenTLSWithErr(host, testCertFilename, testKeyFilename)
-		if err != nil {
-			t.Fatalf("Error on server_test ListenTLSWithErr: %s", err.Error())
-		}
-	}()
+	go ListenVirtual(config.Server{ListeningAddr: host, CertFile: certFile.Name(), KeyFile: keyFile.Name()})
 
 	defer func() {
 		go secondary.Close()