Merge "Scenario tests: improve test http server"

This commit is contained in:
Jenkins 2016-10-12 21:38:47 +00:00 committed by Gerrit Code Review
commit 451faa2534
4 changed files with 129 additions and 35 deletions

View File

@ -0,0 +1 @@
golang

View File

@ -0,0 +1 @@
golang

View File

@ -0,0 +1,87 @@
package main
import (
"flag"
"fmt"
"io"
"net/http"
"sync"
"time"
)
var sess_cookie http.Cookie
var resp string
type ConnectionCount struct {
mu sync.Mutex
cur_conn int
max_conn int
total_conn int
}
var scoreboard ConnectionCount
func (cc *ConnectionCount) open() {
cc.mu.Lock()
defer cc.mu.Unlock()
cc.cur_conn++
cc.total_conn++
}
func (cc *ConnectionCount) close() {
cc.mu.Lock()
defer cc.mu.Unlock()
if cc.cur_conn > cc.max_conn {
cc.max_conn = cc.cur_conn
}
cc.cur_conn--
}
func (cc *ConnectionCount) stats() (int, int) {
cc.mu.Lock()
defer cc.mu.Unlock()
return cc.max_conn, cc.total_conn
}
func root_handler(w http.ResponseWriter, r *http.Request) {
scoreboard.open()
defer scoreboard.close()
http.SetCookie(w, &sess_cookie)
io.WriteString(w, resp)
}
func slow_handler(w http.ResponseWriter, r *http.Request) {
scoreboard.open()
defer scoreboard.close()
time.Sleep(3 * time.Second)
http.SetCookie(w, &sess_cookie)
io.WriteString(w, resp)
}
func stats_handler(w http.ResponseWriter, r *http.Request) {
http.SetCookie(w, &sess_cookie)
max_conn, total_conn := scoreboard.stats()
fmt.Fprintf(w, "max_conn=%d\ntotal_conn=%d\n", max_conn, total_conn)
}
func main() {
portPtr := flag.Int("port", 8080, "TCP port to listen on")
idPtr := flag.Int("id", 1, "Server ID")
flag.Parse()
resp = fmt.Sprintf("server%d", *idPtr)
sess_cookie.Name = "JESSIONID"
sess_cookie.Value = fmt.Sprintf("%d", *idPtr)
http.HandleFunc("/", root_handler)
http.HandleFunc("/slow", slow_handler)
http.HandleFunc("/stats", stats_handler)
portStr := fmt.Sprintf(":%d", *portPtr)
http.ListenAndServe(portStr, nil)
}

View File

@ -17,7 +17,9 @@ try:
from http import cookiejar as cookielib from http import cookiejar as cookielib
except ImportError: except ImportError:
import cookielib import cookielib
import os
import shlex import shlex
import shutil
import socket import socket
import subprocess import subprocess
import tempfile import tempfile
@ -47,6 +49,9 @@ from octavia.tests.tempest.v1.clients import pools_client
config = config.CONF config = config.CONF
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
HTTPD_SRC = os.path.abspath(
os.path.join(os.path.dirname(__file__),
'../../../contrib/httpd.go'))
class BaseTestCase(manager.NetworkScenarioTest): class BaseTestCase(manager.NetworkScenarioTest):
@ -221,6 +226,18 @@ class BaseTestCase(manager.NetworkScenarioTest):
waiters.wait_for_server_status(self.servers_client, waiters.wait_for_server_status(self.servers_client,
value, 'ACTIVE') value, 'ACTIVE')
def _build_static_httpd(self):
"""Compile test httpd as a static binary
returns file path of resulting binary file
"""
builddir = tempfile.mkdtemp()
shutil.copyfile(HTTPD_SRC, os.path.join(builddir, 'httpd.go'))
self.execute('go build -ldflags '
'"-linkmode external -extldflags -static" '
'httpd.go', cwd=builddir)
return os.path.join(builddir, 'httpd')
def _start_servers(self): def _start_servers(self):
"""Start one or more backends """Start one or more backends
@ -236,46 +253,30 @@ class BaseTestCase(manager.NetworkScenarioTest):
ip_address=ip, ip_address=ip,
private_key=private_key) private_key=private_key)
# Write a backend's response into a file httpd = self._build_static_httpd()
resp = ('echo -ne "HTTP/1.1 200 OK\r\nContent-Length: 7\r\n'
'Set-Cookie:JSESSIONID=%(s_id)s\r\nConnection: close\r\n'
'Content-Type: text/html; '
'charset=UTF-8\r\n\r\n%(server)s"; cat >/dev/null')
with tempfile.NamedTemporaryFile() as script:
script.write(resp % {'s_id': server_name[-1],
'server': server_name})
script.flush()
with tempfile.NamedTemporaryFile() as key: with tempfile.NamedTemporaryFile() as key:
key.write(private_key) key.write(private_key)
key.flush() key.flush()
self.copy_file_to_host(script.name, self.copy_file_to_host(httpd,
"/tmp/script1", "/dev/shm/httpd",
ip, ip,
username, key.name) username, key.name)
# Start netcat # Start httpd
start_server = ('while true; do ' start_server = ('sudo sh -c "ulimit -n 100000; nohup '
'sudo nc -ll -p %(port)s -e sh /tmp/%(script)s; ' '/dev/shm/httpd -id %(id)s '
'done > /dev/null &') '-port %(port)s &"')
cmd = start_server % {'port': self.port1, cmd = start_server % {'id': server_name[-1],
'script': 'script1'} 'port': self.port1}
ssh_client.exec_command(cmd) ssh_client.exec_command(cmd)
# In single server case run a second server on an alternate port
if len(self.server_ips) == 1: if len(self.server_ips) == 1:
with tempfile.NamedTemporaryFile() as script: cmd = start_server % {'id': '2',
script.write(resp % {'s_id': 2, 'port': self.port2}
'server': 'server2'})
script.flush()
with tempfile.NamedTemporaryFile() as key:
key.write(private_key)
key.flush()
self.copy_file_to_host(script.name,
"/tmp/script2", ip,
username, key.name)
cmd = start_server % {'port': self.port2,
'script': 'script2'}
ssh_client.exec_command(cmd) ssh_client.exec_command(cmd)
# Allow ssh_client connection to fall out of scope
def _create_listener(self, load_balancer_id, default_pool_id=None): def _create_listener(self, load_balancer_id, default_pool_id=None):
"""Create a listener with HTTP protocol listening on port 80.""" """Create a listener with HTTP protocol listening on port 80."""
@ -754,9 +755,13 @@ class BaseTestCase(manager.NetworkScenarioTest):
"-i %(pkey)s %(file1)s %(dest)s" % {'pkey': pkey, "-i %(pkey)s %(file1)s %(dest)s" % {'pkey': pkey,
'file1': file_from, 'file1': file_from,
'dest': dest}) 'dest': dest})
return self.execute(cmd)
def execute(self, cmd, cwd=None):
args = shlex.split(cmd.encode('utf-8')) args = shlex.split(cmd.encode('utf-8'))
subprocess_args = {'stdout': subprocess.PIPE, subprocess_args = {'stdout': subprocess.PIPE,
'stderr': subprocess.STDOUT} 'stderr': subprocess.STDOUT,
'cwd': cwd}
proc = subprocess.Popen(args, **subprocess_args) proc = subprocess.Popen(args, **subprocess_args)
stdout, stderr = proc.communicate() stdout, stderr = proc.communicate()
if proc.returncode != 0: if proc.returncode != 0: