예제 #1
0
 def test_400_07(self):
     url = TestEnv.mkurl("https", "push", "/006-push7.html")
     r = TestEnv.nghttp().get(url)
     assert 200 == r["response"]["status"]
     promises = r["streams"][r["response"]["id"]]["promises"]
     assert 1 == len(promises)
     assert '/006/006.css' == promises[0]["request"]["header"][":path"]
예제 #2
0
 def test_103_06(self):
     url = TestEnv.mkurl("https", "test1", "/index.html")
     r = TestEnv.curl_get(url, options=[ "--http1.1" ])
     assert 0 == r["rv"]
     assert "response" in r
     assert "upgrade" in r["response"]["header"]
     assert "h2" == r["response"]["header"]["upgrade"]
예제 #3
0
 def test_103_01(self):
     url = TestEnv.mkurl("http", "test1", "/index.html")
     r = TestEnv.curl_get(url)
     assert 0 == r["rv"]
     assert "response" in r
     assert "upgrade" in r["response"]["header"]
     assert "h2c" == r["response"]["header"]["upgrade"]
예제 #4
0
 def test_100_03(self):
     url = TestEnv.mkurl("https", "cgi", "/")
     hostname = ("test1.%s" % TestEnv.HTTP_TLD)
     r = TestEnv.curl_get(url, 5, [ "-H", "Host:%s" % hostname ])
     assert 200 == r["response"]["status"]
     assert "HTTP/2" == r["response"]["protocol"]
     assert "text/html" == r["response"]["header"]["content-type"]
예제 #5
0
 def test_100_02(self):
     url = TestEnv.mkurl("https", "cgi", "/hello.py")
     hostname = ("cgi-alias.%s" % TestEnv.HTTP_TLD)
     r = TestEnv.curl_get(url, 5, [ "-H", "Host:%s" % hostname ])
     assert 200 == r["response"]["status"]
     assert "HTTP/2" == r["response"]["protocol"]
     assert hostname == r["response"]["json"]["host"]
예제 #6
0
 def test_002_01(self):
     url = TestEnv.mkurl("http", "test1", "/alive.json")
     r = TestEnv.curl_get(url, 5)
     assert 200 == r["response"]["status"]
     assert "HTTP/1.1" == r["response"]["protocol"]
     assert True == r["response"]["json"]["alive"]
     assert "test1" == r["response"]["json"]["host"]
예제 #7
0
 def test_002_02(self):
     url = TestEnv.mkurl("https", "test1", "/alive.json")
     r = TestEnv.curl_get(url, 5)
     assert 200 == r["response"]["status"]
     assert True == r["response"]["json"]["alive"]
     assert "test1" == r["response"]["json"]["host"]
     assert "application/json" == r["response"]["header"]["content-type"]
예제 #8
0
 def test_400_32(self):
     url = TestEnv.mkurl("https", "hints", "/006-nohints.html")
     r = TestEnv.nghttp().get(url)
     assert 200 == r["response"]["status"]
     promises = r["streams"][r["response"]["id"]]["promises"]
     assert 1 == len(promises)
     assert not "previous" in r["response"]
예제 #9
0
    def test_003_21(self):
        url = TestEnv.mkurl("https", "test1", "/index.html")
        r = TestEnv.curl_get(url, 5, [ "-I" ])
        assert 200 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        s = self.clean_header(r["response"]["body"])
        assert '''HTTP/2 200 
content-length: 2007
content-type: text/html

''' == s

        r = TestEnv.curl_get(url, 5, [ "-I", url ])
        assert 200 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        s = self.clean_header(r["response"]["body"])
        assert '''HTTP/2 200 
content-length: 2007
content-type: text/html

HTTP/2 200 
content-length: 2007
content-type: text/html

''' == s
예제 #10
0
 def test_200_03(self):
     url = TestEnv.mkurl("https", "cgi", "/hecho.py")
     for hex in [ "10", "7f" ]:
         r = TestEnv.curl_post_data(url, "name=x%%%s&value=yz" % hex)
         assert 0 != r["rv"]
         r = TestEnv.curl_post_data(url, "name=x&value=y%%%sz" % hex)
         assert 0 != r["rv"]
예제 #11
0
    def nghttp_upload_stat(self, fname, options=None):
        url = TestEnv.mkurl("https", "cgi", "/proxy/upload.py")
        fpath = os.path.join(TestEnv.GEN_DIR, fname)

        r = TestEnv.nghttp().upload_file(url, fpath, options=options)
        assert r["rv"] == 0
        assert r["response"]["status"] >= 200 and r["response"]["status"] < 300
        assert r["response"]["header"]["location"]
예제 #12
0
 def check_necho(self, n, text):
     url = TestEnv.mkurl("https", "cgi", "/necho.py")
     r = TestEnv.curl_get(url, 5, [ "-F", ("count=%d" % (n)), "-F", ("text=%s" % (text)) ])
     assert 200 == r["response"]["status"]
     exp = ""
     for i in range(n):
         exp += text + "\n"
     assert exp == r["response"]["body"]
예제 #13
0
 def test_006_02(self):
     url = TestEnv.mkurl("https", "test1", "/002.jpg")
     r = TestEnv.nghttp().assets(url)
     assert 0 == r["rv"]
     assert 1 == len(r["assets"])
     assert r["assets"] == [
         { "status": 200, "size": "88K", "path" : "/002.jpg" }
     ]
예제 #14
0
 def test_005_01(self):
     url = TestEnv.mkurl("https", "cgi", "/.well-known/h2/state")
     r = TestEnv.curl_get(url, 5)
     assert 200 == r["response"]["status"]
     st = r["response"]["json"]
     
     # remove some parts that are very dependant on client/lib versions
     # or connection time etc.
     del st["settings"]["SETTINGS_INITIAL_WINDOW_SIZE"]
     del st["peerSettings"]["SETTINGS_INITIAL_WINDOW_SIZE"]
     del st["streams"]["1"]["created"]
     del st["streams"]["1"]["flowOut"]
     del st["stats"]["in"]["frames"]
     del st["stats"]["in"]["octets"]
     del st["stats"]["out"]["frames"]
     del st["stats"]["out"]["octets"]
     del st["connFlowOut"]
     
     assert st == {
         "version" : "draft-01",
         "settings" : {
             "SETTINGS_MAX_CONCURRENT_STREAMS": 100,
             "SETTINGS_MAX_FRAME_SIZE": 16384,
             "SETTINGS_ENABLE_PUSH": 0
         },
         "peerSettings" : {
             "SETTINGS_MAX_CONCURRENT_STREAMS": 100,
             "SETTINGS_MAX_FRAME_SIZE": 16384,
             "SETTINGS_ENABLE_PUSH": 0,
             "SETTINGS_HEADER_TABLE_SIZE": 4096,
             "SETTINGS_MAX_HEADER_LIST_SIZE": -1
         },
         "connFlowIn": 2147483647,
         "sentGoAway": 0,
         "streams": {
             "1": {
                 "state": "HALF_CLOSED_REMOTE",
                 "flowIn": 65535,
                 "dataIn": 0,
                 "dataOut": 0
             }
         },
         "stats": {
             "in": {
                 "requests": 1,
                 "resets": 0, 
             },
             "out": {
                 "responses": 0,
             },
             "push": {
                 "cacheDigest": "AQg",
                 "promises": 0,
                 "submits": 0,
                 "resets": 0
             }
         }
     }
예제 #15
0
 def test_400_52(self):
     url = TestEnv.mkurl("https", "push", "/006-push.html")
     r = TestEnv.nghttp().get(url, options=[ '-H', 'accept-push-policy: head'])
     assert 200 == r["response"]["status"]
     promises = r["streams"][r["response"]["id"]]["promises"]
     assert 1 == len(promises)
     assert '/006/006.css' == promises[0]["request"]["header"][":path"]
     assert "" == promises[0]["response"]["body"]
     assert 0 == len(promises[0]["response"]["body"])
예제 #16
0
 def test_600_01(self):
     url = TestEnv.mkurl("https", "cgi", "/h2proxy/hello.py")
     r = TestEnv.curl_get(url, 5)
     assert 200 == r["response"]["status"]
     assert "HTTP/2.0" == r["response"]["json"]["protocol"]
     assert "on" == r["response"]["json"]["https"]
     assert "" != r["response"]["json"]["ssl_protocol"]
     assert "on" == r["response"]["json"]["h2"]
     assert "off" == r["response"]["json"]["h2push"]
예제 #17
0
 def test_006_05(self):
     url = TestEnv.mkurl("https", "test1", "/003.html")
     r = TestEnv.nghttp().assets(url, options=[ "--window-bits=24" ])
     assert 0 == r["rv"]
     assert 2 == len(r["assets"])
     assert r["assets"] == [
         { "status": 200, "size": "316", "path": "/003.html" },
         { "status": 200, "size": "88K", "path": "/003/003_img.jpg" }
     ]
예제 #18
0
 def test_200_02(self):
     url = TestEnv.mkurl("https", "cgi", "/hecho.py")
     for x in range(1, 32):
         if 9 != x:
             r = TestEnv.curl_post_data(url, "name=x&value=y%%%02x" % x)
             if x in [ 10, 13 ]:
                 assert 0 == r["rv"], "unexpected exit code for char 0x%02x" % x
                 assert 200 == r["response"]["status"], "unexpected status for char 0x%02x" % x
             else:
                 assert 0 != r["rv"], "unexpected exit code for char 0x%02x" % x
예제 #19
0
 def test_201_01(self):
     url = TestEnv.mkurl("https", "test1", "/006/006.css")
     r = TestEnv.curl_get(url)
     assert 200 == r["response"]["status"]
     lm = r["response"]["header"]["last-modified"]
     assert lm
     r = TestEnv.curl_get(url, options=[ "-H", "if-modified-since: %s" % lm])
     assert 304 == r["response"]["status"]
     r = TestEnv.curl_get(url, options=[ "-H", "if-modified-since: Tue, 04 Sep 2010 11:51:59 GMT"])
     assert 200 == r["response"]["status"]
예제 #20
0
 def test_201_02(self):
     url = TestEnv.mkurl("https", "test1", "/006/006.css")
     r = TestEnv.curl_get(url)
     assert 200 == r["response"]["status"]
     etag = r["response"]["header"]["etag"]
     assert etag
     r = TestEnv.curl_get(url, options=[ "-H", "if-none-match: %s" % etag])
     assert 304 == r["response"]["status"]
     r = TestEnv.curl_get(url, options=[ "-H", "if-none-match: dummy"])
     assert 200 == r["response"]["status"]
예제 #21
0
 def test_400_31(self):
     url = TestEnv.mkurl("https", "hints", "/006-hints.html")
     r = TestEnv.nghttp().get(url)
     assert 200 == r["response"]["status"]
     promises = r["streams"][r["response"]["id"]]["promises"]
     assert 1 == len(promises)
     early = r["response"]["previous"]
     assert early
     assert 103 == int(early["header"][":status"])
     assert early["header"]["link"]
예제 #22
0
 def test_006_04(self):
     url = TestEnv.mkurl("https", "test1", "/006.html")
     r = TestEnv.nghttp().assets(url)
     assert 0 == r["rv"]
     assert 3 == len(r["assets"])
     assert r["assets"] == [
         { "status": 200, "size": "543", "path": "/006.html" },
         { "status": 200, "size": "216", "path": "/006/006.css" },
         { "status": 200, "size": "839", "path": "/006/006.js" }
     ]
예제 #23
0
    def nghttp_post_and_verify(self, fname, options=None):
        url = TestEnv.mkurl("https", "cgi", "/echo.py")
        fpath = os.path.join(TestEnv.GEN_DIR, fname)

        r = TestEnv.nghttp().upload(url, fpath, options=options)
        assert r["rv"] == 0
        assert r["response"]["status"] >= 200 and r["response"]["status"] < 300

        with open(TestEnv.e2e_src( fpath ), mode='rb') as file:
            src = file.read()
        assert src == r["response"]["body"]
예제 #24
0
    def curl_upload_and_verify(self, fname, options=None):
        url = TestEnv.mkurl("https", "cgi", "/upload.py")
        fpath = os.path.join(TestEnv.GEN_DIR, fname)
        r = TestEnv.curl_upload(url, fpath, options=options)
        assert r["rv"] == 0
        assert r["response"]["status"] >= 200 and r["response"]["status"] < 300

        r2 = TestEnv.curl_get( r["response"]["header"]["location"])
        assert r2["rv"] == 0
        assert r2["response"]["status"] == 200 
        with open(TestEnv.e2e_src( fpath ), mode='rb') as file:
            src = file.read()
        assert src == r2["response"]["body"]
예제 #25
0
 def check_nghttp_body(self, ref_input, nghttp_output):
     with open(TestEnv.e2e_src( os.path.join(TestEnv.GEN_DIR, ref_input) ), mode='rb') as f:
         refbody = f.read()
     with open(TestEnv.e2e_src( nghttp_output), mode='rb') as f:
         text = f.read()
     o = TestEnv.nghttp().parse_output(text)
     assert "response" in o
     assert "body" in o["response"]
     if refbody != o["response"]["body"]:
         with open(TestEnv.e2e_src( os.path.join(TestEnv.GEN_DIR, '%s.parsed' % ref_input) ), mode='wb') as f:
             f.write( o["response"]["body"] )
     assert len(refbody) == len(o["response"]["body"])
     assert refbody == o["response"]["body"]
예제 #26
0
def setup_module(module):
    print("setup_module: %s" % module.__name__)
    TestEnv.init()
    HttpdConf(
    ).start_vhost( TestEnv.HTTPS_PORT, "push", docRoot="htdocs/test1", withSSL=True
    ).add_line("""    Protocols h2 http/1.1"

    RewriteEngine on
    RewriteRule ^/006-push(.*)?\.html$ /006.html
    <Location /006-push.html>
        Header add Link "</006/006.css>;rel=preload"
        Header add Link "</006/006.js>;rel=preloadX"
    </Location>
    <Location /006-push2.html>
        Header add Link "</006/006.css>;rel=preloadX, </006/006.js>; rel=preload"
    </Location>
    <Location /006-push3.html>
        Header add Link "</006/006.css>;rel=preloa,</006/006.js>;rel=preload"
    </Location>
    <Location /006-push4.html>
        Header add Link "</006/006.css;rel=preload, </006/006.js>; preload"
    </Location>
    <Location /006-push5.html>
        Header add Link '</006/006.css>;rel="preload push"'
    </Location>
    <Location /006-push6.html>
        Header add Link '</006/006.css>;rel="push preload"'
    </Location>
    <Location /006-push7.html>
        Header add Link '</006/006.css>;rel="abc preload push"'
    </Location>
    <Location /006-push8.html>
        Header add Link '</006/006.css>;rel="preload"; nopush'
    </Location>
    <Location /006-push20.html>
        H2PushResource "/006/006.css" critical
        H2PushResource "/006/006.js"
    </Location>    
    <Location /006-push30.html>
        H2Push off
        Header add Link '</006/006.css>;rel="preload"'
    </Location>
    <Location /006-push31.html>
        H2PushResource "/006/006.css" critical
    </Location>
    <Location /006-push32.html>
        Header add Link "</006/006.css>;rel=preload"
    </Location>
    """).end_vhost(
    ).install()
    assert TestEnv.apache_restart() == 0
예제 #27
0
    def test_400_20(self):
        url = TestEnv.mkurl("https", "push", "/006-push20.html")
        r = TestEnv.nghttp().get(url)
        assert 200 == r["response"]["status"]
        promises = r["streams"][r["response"]["id"]]["promises"]
        assert 2 == len(promises)

        fpath = os.path.join(TestEnv.GEN_DIR, "data-400-20")
        with open(fpath, 'w') as f:
            f.write("test upload data")
        r = TestEnv.nghttp().upload(url, fpath)
        assert 200 == r["response"]["status"]
        promises = r["streams"][r["response"]["id"]]["promises"]
        assert 0 == len(promises)
예제 #28
0
 def test_101_05(self):
     url = TestEnv.mkurl("https", "ssl", "/ssl-client-verify/index.html")
     r = TestEnv.run( [ TestEnv.H2LOAD, "-n", "10", "-c", "1", "-m", "1", "-vvvv", 
         "https://%s:%s/ssl-client-verify/index.html" % (TestEnv.HTTPD_ADDR, TestEnv.HTTPS_PORT)] )
     assert 0 == r["rv"]
     r = TestEnv.h2load_status(r)
     assert 10 == r["h2load"]["requests"]["total"]
     assert 10 == r["h2load"]["requests"]["started"]
     assert 10 == r["h2load"]["requests"]["done"]
     assert 0 == r["h2load"]["requests"]["succeeded"]
     assert 0 == r["h2load"]["status"]["2xx"]
     assert 0 == r["h2load"]["status"]["3xx"]
     assert 0 == r["h2load"]["status"]["4xx"]
     assert 0 == r["h2load"]["status"]["5xx"]
예제 #29
0
    def test_003_02(self):
        with open(TestEnv.e2e_src( "htdocs/test1/index.html"), mode='rb') as file:
            src = file.read()

        url = TestEnv.mkurl("https", "test1", "/index.html")
        r = TestEnv.curl_get(url, 5)
        assert 200 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        assert src == r["response"]["body"]

        url = TestEnv.mkurl("https", "test1", "/index.html")
        r = TestEnv.curl_get(url, 5, [ "--http1.1" ])
        assert 200 == r["response"]["status"]
        assert "HTTP/1.1" == r["response"]["protocol"]
        assert src == r["response"]["body"]
예제 #30
0
    def nghttp_upload_and_verify(self, fname, options=None):
        url = TestEnv.mkurl("https", "cgi", "/proxy/upload.py")
        fpath = os.path.join(TestEnv.GEN_DIR, fname)

        r = TestEnv.nghttp().upload_file(url, fpath, options=options)
        assert r["rv"] == 0
        assert r["response"]["status"] >= 200 and r["response"]["status"] < 300
        assert r["response"]["header"]["location"]

        # why is the scheme wrong?
        r2 = TestEnv.nghttp().get(re.sub(r'http:', 'https:', r["response"]["header"]["location"]))
        assert r2["rv"] == 0
        assert r2["response"]["status"] == 200 
        with open(TestEnv.e2e_src( fpath ), mode='rb') as file:
            src = file.read()
        assert src == r2["response"]["body"]
예제 #31
0
 def test_003_41(self, n):
     url = TestEnv.mkurl("https", "cgi", "/mnot164.py?count=%d&text=X" % (n))
     r = TestEnv.curl_get(url, 5)
     assert 200 == r["response"]["status"]
     assert "HTTP/2" == r["response"]["protocol"]
     assert n == len(r["response"]["body"])
예제 #32
0
class TestStore:

    def setup_method(self, method):
        print("setup_method: %s" % method.__name__)

    def teardown_method(self, method):
        print("teardown_method: %s" % method.__name__)
    
    # check SSL environment variables from CGI script
    def test_003_01(self):
        url = TestEnv.mkurl("https", "cgi", "/hello.py")
        r = TestEnv.curl_get(url, 5, ["--tlsv1.2"])
        assert 200 == r["response"]["status"]
        assert "HTTP/2.0" == r["response"]["json"]["protocol"]
        assert "on" == r["response"]["json"]["https"]
        tls_version = r["response"]["json"]["ssl_protocol"]
        assert tls_version in ["TLSv1.2", "TLSv1.3"]
        assert "on" == r["response"]["json"]["h2"]
        assert "off" == r["response"]["json"]["h2push"]

        r = TestEnv.curl_get(url, 5, [ "--http1.1", "--tlsv1.2"])
        assert 200 == r["response"]["status"]
        assert "HTTP/1.1" == r["response"]["json"]["protocol"]
        assert "on" == r["response"]["json"]["https"]
        tls_version = r["response"]["json"]["ssl_protocol"]
        assert tls_version in ["TLSv1.2", "TLSv1.3"]
        assert "" == r["response"]["json"]["h2"]
        assert "" == r["response"]["json"]["h2push"]

    # retrieve a html file from the server and compare it to its source
    def test_003_02(self):
        with open(TestEnv.e2e_src( "htdocs/test1/index.html"), mode='rb') as file:
            src = file.read()

        url = TestEnv.mkurl("https", "test1", "/index.html")
        r = TestEnv.curl_get(url, 5)
        assert 200 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        assert src == r["response"]["body"]

        url = TestEnv.mkurl("https", "test1", "/index.html")
        r = TestEnv.curl_get(url, 5, [ "--http1.1" ])
        assert 200 == r["response"]["status"]
        assert "HTTP/1.1" == r["response"]["protocol"]
        assert src == r["response"]["body"]

    # retrieve chunked content from a cgi script
    def check_necho(self, n, text):
        url = TestEnv.mkurl("https", "cgi", "/necho.py")
        r = TestEnv.curl_get(url, 5, [ "-F", ("count=%d" % (n)), "-F", ("text=%s" % (text)) ])
        assert 200 == r["response"]["status"]
        exp = ""
        for i in range(n):
            exp += text + "\n"
        assert exp == r["response"]["body"].decode('utf-8')
    
    def test_003_10(self):
        self.check_necho(10, "0123456789")

    def test_003_11(self):
        self.check_necho(100, "0123456789")

    def test_003_12(self):
        self.check_necho(1000, "0123456789")

    def test_003_13(self):
        self.check_necho(10000, "0123456789")

    def test_003_14(self):
        self.check_necho(100000, "0123456789")

    # github issue #126
    def test_003_20(self):
        url = TestEnv.mkurl("https", "test1", "/006/")
        r = TestEnv.curl_get(url, 5)
        assert 200 == r["response"]["status"]
        body = r["response"]["body"].decode('utf-8')
        # our doctype varies between branches and in time, lets not compare
        body = re.sub(r'^<!DOCTYPE[^>]+>', '', body)
        assert '''
<html>
 <head>
  <title>Index of /006</title>
 </head>
 <body>
<title>My Header Title</title>
<ul><li><a href="/"> Parent Directory</a></li>
<li><a href="006.css"> 006.css</a></li>
<li><a href="006.js"> 006.js</a></li>
<li><a href="header.html"> header.html</a></li>
</ul>
</body></html>
''' == body

    # github issue #133
    def clean_header(self, s):
        s = re.sub(r'\r\n', '\n', s, flags=re.MULTILINE)
        s = re.sub(r'^date:.*\n', '', s, flags=re.MULTILINE)
        s = re.sub(r'^server:.*\n', '', s, flags=re.MULTILINE)
        s = re.sub(r'^last-modified:.*\n', '', s, flags=re.MULTILINE)
        s = re.sub(r'^etag:.*\n', '', s, flags=re.MULTILINE)
        s = re.sub(r'^vary:.*\n', '', s, flags=re.MULTILINE)
        return re.sub(r'^accept-ranges:.*\n', '', s, flags=re.MULTILINE)
        
    def test_003_21(self):
        url = TestEnv.mkurl("https", "test1", "/index.html")
        r = TestEnv.curl_get(url, 5, [ "-I" ])
        assert 200 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        s = self.clean_header(r["response"]["body"].decode('utf-8'))
        assert '''HTTP/2 200 
content-length: 2007
content-type: text/html

''' == s

        r = TestEnv.curl_get(url, 5, [ "-I", url ])
        assert 200 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        s = self.clean_header(r["response"]["body"].decode('utf-8'))
        assert '''HTTP/2 200 
content-length: 2007
content-type: text/html

HTTP/2 200 
content-length: 2007
content-type: text/html

''' == s

    # test conditionals: if-modified-since
    @pytest.mark.parametrize("path", [
        "/004.html", "/proxy/004.html", "/h2proxy/004.html"
    ])
    def test_003_30(self, path):
        url = TestEnv.mkurl("https", "test1", path)
        r = TestEnv.curl_get(url, 5)
        assert 200 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        h = r["response"]["header"]
        assert "last-modified" in h
        lastmod = h["last-modified"]
        r = TestEnv.curl_get(url, 5, [ '-H', ("if-modified-since: %s" % lastmod) ])
        assert 304 == r["response"]["status"]

    # test conditionals: if-etag
    @pytest.mark.parametrize("path", [
        "/004.html", "/proxy/004.html", "/h2proxy/004.html"
    ])
    def test_003_31(self, path):
        url = TestEnv.mkurl("https", "test1", path)
        r = TestEnv.curl_get(url, 5)
        assert 200 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        h = r["response"]["header"]
        assert "etag" in h
        etag = h["etag"]
        r = TestEnv.curl_get(url, 5, [ '-H', ("if-none-match: %s" % etag) ])
        assert 304 == r["response"]["status"]

    # test various response body lengths to work correctly 
    def test_003_40(self):
        n = 1001
        while n <= 1025024:
            url = TestEnv.mkurl("https", "cgi", "/mnot164.py?count=%d&text=X" % (n))
            r = TestEnv.curl_get(url, 5)
            assert 200 == r["response"]["status"]
            assert "HTTP/2" == r["response"]["protocol"]
            assert n == len(r["response"]["body"])
            n *= 2

    # test various response body lengths to work correctly 
    @pytest.mark.skipif(not TestEnv.has_nghttp(), reason="no nghttp command available")
    @pytest.mark.parametrize("n", [
        0, 1, 1291, 1292, 80000, 80123, 81087, 98452
    ])
    def test_003_41(self, n):
        url = TestEnv.mkurl("https", "cgi", "/mnot164.py?count=%d&text=X" % (n))
        r = TestEnv.curl_get(url, 5)
        assert 200 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        assert n == len(r["response"]["body"])
        
    # test ranges
    @pytest.mark.parametrize("path", [
        "/004.html", "/proxy/004.html", "/h2proxy/004.html"
    ])
    def test_003_50(self, path):
        # check that the resource supports ranges and we see its raw content-length
        url = TestEnv.mkurl("https", "test1", path)
        r = TestEnv.curl_get(url, 5)
        assert 200 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        h = r["response"]["header"]
        assert "accept-ranges" in h
        assert "bytes" == h["accept-ranges"]
        assert "content-length" in h
        clen = h["content-length"]
        # get the first 1024 bytes of the resource, 206 status, but content-length as original
        r = TestEnv.curl_get(url, 5, options=[ "-H", "range: bytes=0-1023"])
        assert 206 == r["response"]["status"]
        assert "HTTP/2" == r["response"]["protocol"]
        assert 1024 == len(r["response"]["body"])
        assert "content-length" in h
        assert clen == h["content-length"]
예제 #33
0
 def setup_method(self, method):
     print("setup_method: %s" % method.__name__)
     self.test_domain = TestEnv.get_method_domain(method)
예제 #34
0
def setup_module(module):
    print("setup_module: %s" % module.__name__)
    TestEnv.init()
예제 #35
0
    <Location /006-hints.html>
        H2PushResource "/006/006.css" critical
    </Location>
    <Location /006-nohints.html>
        Header add Link "</006/006.css>;rel=preload"
    </Location>
    """).end_vhost(
    ).install()
    assert TestEnv.apache_restart() == 0
        
def teardown_module(module):
    print("teardown_module: %s" % module.__name__)
    assert TestEnv.apache_stop() == 0

# The push tests depend on "nghttp"
@pytest.mark.skipif(not TestEnv.has_nghttp(), reason="no nghttp command available")
class TestStore:

    def setup_method(self, method):
        print("setup_method: %s" % method.__name__)

    def teardown_method(self, method):
        print("teardown_method: %s" % method.__name__)
    
    # H2EarlyHints enabled in general, check that it works for H2PushResource
    def test_401_31(self):
        url = TestEnv.mkurl("https", "hints", "/006-hints.html")
        r = TestEnv.nghttp().get(url)
        assert 200 == r["response"]["status"]
        promises = r["streams"][r["response"]["id"]]["promises"]
        assert 1 == len(promises)
예제 #36
0
 def test_310_100(self, confline, dns_lists, md_count):
     HttpdConf(text=confline).install()
     assert TestEnv.apache_restart() == 0
     for i in range(0, len(dns_lists)):
         TestEnv.check_md(dns_lists[i], state=1)
예제 #37
0
 def setup_method(self, method):
     print("setup_method: %s" % method.__name__)
     TestEnv.httpd_error_log_clear()
     TestEnv.clear_store()
     self.test_domain = TestEnv.get_method_domain(method)
예제 #38
0
 def test_702_009(self):
     domain = self.test_domain
     domains = [domain]
     #
     # prepare md
     conf = HttpdConf()
     conf.add_admin("admin@" + domain)
     conf.add_drive_mode("auto")
     conf.add_renew_window("10d")
     conf.add_md(domains)
     conf.add_vhost(domain)
     conf.install()
     #
     # restart (-> drive), check that md+cert is in store, TLS is up
     assert TestEnv.apache_restart() == 0
     assert TestEnv.await_completion([domain])
     TestEnv.check_md_complete(domain)
     cert1 = CertUtil(TestEnv.store_domain_file(domain, 'pubcert.pem'))
     # compare with what md reports as status
     stat = TestEnv.get_certificate_status(domain)
     assert stat['rsa']['serial'] == cert1.get_serial()
     #
     # create self-signed cert, with critical remaining valid duration -> drive again
     TestEnv.create_self_signed_cert([domain], {
         "notBefore": -120,
         "notAfter": 2
     },
                                     serial=7029)
     cert3 = CertUtil(TestEnv.store_domain_file(domain, 'pubcert.pem'))
     assert cert3.get_serial() == '1B75'
     assert TestEnv.apache_restart() == 0
     stat = TestEnv.get_certificate_status(domain)
     assert stat['rsa']['serial'] == cert3.get_serial()
     #
     # cert should renew and be different afterwards
     assert TestEnv.await_completion([domain], must_renew=True)
     stat = TestEnv.get_certificate_status(domain)
     assert stat['rsa']['serial'] != cert3.get_serial()
예제 #39
0
 def test_702_001(self):
     domain = self.test_domain
     # generate config with one MD
     domains = [domain, "www." + domain]
     conf = HttpdConf()
     conf.add_admin("admin@" + domain)
     conf.add_drive_mode("auto")
     conf.add_md(domains)
     conf.install()
     #
     # restart, check that MD is synched to store
     assert TestEnv.apache_restart() == 0
     TestEnv.check_md(domains)
     stat = TestEnv.get_md_status(domain)
     assert stat["watched"] == 0
     #
     # add vhost for MD, restart should drive it
     conf.add_vhost(domains)
     conf.install()
     assert TestEnv.apache_restart() == 0
     assert TestEnv.await_completion([domain])
     TestEnv.check_md_complete(domain)
     stat = TestEnv.get_md_status(domain)
     assert stat["watched"] == 1
     cert = TestEnv.get_cert(domain)
     assert domain in cert.get_san_list()
     #
     # challenges should have been removed
     # file system needs to have correct permissions
     TestEnv.check_dir_empty(TestEnv.store_challenges())
     TestEnv.check_file_permissions(domain)
예제 #40
0
 def test_702_030(self):
     domain = self.test_domain
     nameX = "test-x." + domain
     nameA = "test-a." + domain
     nameB = "test-b." + domain
     domains = [nameX, nameA, nameB]
     #
     # generate 1 MD and 2 vhosts
     conf = HttpdConf()
     conf.add_admin("admin@" + domain)
     conf.add_md(domains)
     conf.add_vhost(nameA)
     conf.add_vhost(nameB)
     conf.install()
     #
     # restart (-> drive), check that MD was synched and completes
     assert TestEnv.apache_restart() == 0
     TestEnv.check_md(domains)
     assert TestEnv.await_completion([nameX])
     TestEnv.check_md_complete(nameX)
     #
     # check: SSL is running OK
     certA = TestEnv.get_cert(nameA)
     assert nameA in certA.get_san_list()
     certB = TestEnv.get_cert(nameB)
     assert nameB in certB.get_san_list()
     assert certA.get_serial() == certB.get_serial()
     #
     # change MD by removing 1st name
     new_list = [nameA, nameB]
     conf = HttpdConf()
     conf.add_admin("admin@" + domain)
     conf.add_md(new_list)
     conf.add_vhost(nameA)
     conf.add_vhost(nameB)
     conf.install()
     # restart, check that host still works and kept the cert
     assert TestEnv.apache_restart() == 0
     TestEnv.check_md(new_list)
     status = TestEnv.get_certificate_status(nameA)
     assert status['rsa']['serial'] == certA.get_serial()
예제 #41
0
 def test_310_203(self):
     dns_list1 = [
         "greenbytes2.de", "www.greenbytes2.de", "mail.greenbytes2.de"
     ]
     dns_list2 = [
         "testdomain.org", "www.testdomain.org", "mail.testdomain.org"
     ]
     TestEnv.a2md(["add"] + dns_list1)
     TestEnv.a2md(["add"] + dns_list2)
     TestEnv.check_md(dns_list1, state=1)
     TestEnv.check_md(dns_list2, state=1)
     HttpdConf(text="""
         MDomain testdomain.org www.testdomain.org mail.testdomain.org
         """).install()
     assert TestEnv.apache_restart() == 0
     # all mds stay in store
     TestEnv.check_md(dns_list1, state=1)
     TestEnv.check_md(dns_list2, state=1)
예제 #42
0
def setup_module(module):
    print("setup_module    module:%s" % module.__name__)
    TestEnv.init()
    TestEnv.check_acme()
예제 #43
0
class TestStore:
    def setup_method(self, method):
        print("setup_method: %s" % method.__name__)

    def teardown_method(self, method):
        print("teardown_method: %s" % method.__name__)

    # upload and GET again using curl, compare to original content
    def curl_upload_and_verify(self, fname, options=None):
        url = TestEnv.mkurl("https", "cgi", "/upload.py")
        fpath = os.path.join(TestEnv.GEN_DIR, fname)
        r = TestEnv.curl_upload(url, fpath, options=options)
        assert r["rv"] == 0
        assert r["response"]["status"] >= 200 and r["response"]["status"] < 300

        r2 = TestEnv.curl_get(r["response"]["header"]["location"])
        assert r2["rv"] == 0
        assert r2["response"]["status"] == 200
        with open(TestEnv.e2e_src(fpath), mode='rb') as file:
            src = file.read()
        assert src == r2["response"]["body"]

    def test_004_01(self):
        self.curl_upload_and_verify("data-1k", ["--http1.1"])
        self.curl_upload_and_verify("data-1k", ["--http2"])

    def test_004_02(self):
        self.curl_upload_and_verify("data-10k", ["--http1.1"])
        self.curl_upload_and_verify("data-10k", ["--http2"])

    def test_004_03(self):
        self.curl_upload_and_verify("data-100k", ["--http1.1"])
        self.curl_upload_and_verify("data-100k", ["--http2"])

    def test_004_04(self):
        self.curl_upload_and_verify("data-1m", ["--http1.1"])
        self.curl_upload_and_verify("data-1m", ["--http2"])

    def test_004_05(self):
        self.curl_upload_and_verify(
            "data-1k", ["-v", "--http1.1", "-H", "Expect: 100-continue"])
        self.curl_upload_and_verify(
            "data-1k", ["-v", "--http2", "-H", "Expect: 100-continue"])

    @pytest.mark.skipif(True,
                        reason="python3 regresses in chunked inputs to cgi")
    def test_004_06(self):
        self.curl_upload_and_verify("data-1k",
                                    ["--http1.1", "-H", "Content-Length: "])
        self.curl_upload_and_verify("data-1k",
                                    ["--http2", "-H", "Content-Length: "])

    @pytest.mark.parametrize("name, value", [
        ("HTTP2", "on"),
        ("H2PUSH", "off"),
        ("H2_PUSHED", ""),
        ("H2_PUSHED_ON", ""),
        ("H2_STREAM_ID", "1"),
        ("H2_STREAM_TAG", r'\d+-1'),
    ])
    def test_004_07(self, name, value):
        url = TestEnv.mkurl("https", "cgi", "/env.py")
        r = TestEnv.curl_post_value(url, "name", name)
        assert r["rv"] == 0
        assert r["response"]["status"] == 200
        m = re.match("{0}=(.*)".format(name),
                     r["response"]["body"].decode('utf-8'))
        assert m
        assert re.match(value, m.group(1))

    # verify that we parse nghttp output correctly
    def check_nghttp_body(self, ref_input, nghttp_output):
        with open(TestEnv.e2e_src(os.path.join(TestEnv.GEN_DIR, ref_input)),
                  mode='rb') as f:
            refbody = f.read()
        with open(TestEnv.e2e_src(nghttp_output), mode='rb') as f:
            text = f.read()
        o = TestEnv.nghttp().parse_output(text)
        assert "response" in o
        assert "body" in o["response"]
        if refbody != o["response"]["body"]:
            with open(TestEnv.e2e_src(
                    os.path.join(TestEnv.GEN_DIR, '%s.parsed' % ref_input)),
                      mode='bw') as f:
                f.write(o["response"]["body"])
        assert len(refbody) == len(o["response"]["body"])
        assert refbody == o["response"]["body"]

    def test_004_20(self):
        self.check_nghttp_body('data-1k', 'data/nghttp-output-1k-1.txt')
        self.check_nghttp_body('data-10k', 'data/nghttp-output-10k-1.txt')
        self.check_nghttp_body('data-100k', 'data/nghttp-output-100k-1.txt')

    # POST some data using nghttp and see it echo'ed properly back
    def nghttp_post_and_verify(self, fname, options=None):
        url = TestEnv.mkurl("https", "cgi", "/echo.py")
        fpath = os.path.join(TestEnv.GEN_DIR, fname)

        r = TestEnv.nghttp().upload(url, fpath, options=options)
        assert r["rv"] == 0
        assert r["response"]["status"] >= 200 and r["response"]["status"] < 300

        with open(TestEnv.e2e_src(fpath), mode='rb') as file:
            src = file.read()
        assert src == r["response"]["body"]

    @pytest.mark.skipif(not TestEnv.has_nghttp(),
                        reason="no nghttp command available")
    def test_004_21(self):
        self.nghttp_post_and_verify("data-1k", [])
        self.nghttp_post_and_verify("data-10k", [])
        self.nghttp_post_and_verify("data-100k", [])
        self.nghttp_post_and_verify("data-1m", [])

    @pytest.mark.skipif(not TestEnv.has_nghttp(),
                        reason="no nghttp command available")
    def test_004_22(self):
        self.nghttp_post_and_verify("data-1k", ["--no-content-length"])
        self.nghttp_post_and_verify("data-10k", ["--no-content-length"])
        self.nghttp_post_and_verify("data-100k", ["--no-content-length"])
        self.nghttp_post_and_verify("data-1m", ["--no-content-length"])

    # upload and GET again using nghttp, compare to original content
    def nghttp_upload_and_verify(self, fname, options=None):
        url = TestEnv.mkurl("https", "cgi", "/upload.py")
        fpath = os.path.join(TestEnv.GEN_DIR, fname)

        r = TestEnv.nghttp().upload_file(url, fpath, options=options)
        assert r["rv"] == 0
        assert r["response"]["status"] >= 200 and r["response"]["status"] < 300
        assert r["response"]["header"]["location"]

        r2 = TestEnv.nghttp().get(r["response"]["header"]["location"])
        assert r2["rv"] == 0
        assert r2["response"]["status"] == 200
        with open(TestEnv.e2e_src(fpath), mode='rb') as file:
            src = file.read()
        assert src == r2["response"]["body"]

    @pytest.mark.skipif(not TestEnv.has_nghttp(),
                        reason="no nghttp command available")
    def test_004_23(self):
        self.nghttp_upload_and_verify("data-1k", [])
        self.nghttp_upload_and_verify("data-10k", [])
        self.nghttp_upload_and_verify("data-100k", [])
        self.nghttp_upload_and_verify("data-1m", [])

    @pytest.mark.skipif(not TestEnv.has_nghttp(),
                        reason="no nghttp command available")
    def test_004_24(self):
        self.nghttp_upload_and_verify("data-1k", ["--expect-continue"])
        self.nghttp_upload_and_verify("data-100k", ["--expect-continue"])

    @pytest.mark.skipif(True,
                        reason="python3 regresses in chunked inputs to cgi")
    def test_004_25(self):
        self.nghttp_upload_and_verify("data-1k", ["--no-content-length"])
        self.nghttp_upload_and_verify("data-10k", ["--no-content-length"])
        self.nghttp_upload_and_verify("data-100k", ["--no-content-length"])
        self.nghttp_upload_and_verify("data-1m", ["--no-content-length"])

    def test_004_30(self):
        # issue: #203
        resource = "data-1k"
        full_length = 1000
        chunk = 200
        self.curl_upload_and_verify(resource, ["-v", "--http2"])
        logfile = os.path.join(TestEnv.HTTPD_LOGS_DIR, "test_004_30")
        if os.path.isfile(logfile):
            os.remove(logfile)
        HttpdConf().add_line("""
LogFormat "{ \\"request\\": \\"%r\\", \\"status\\": %>s, \\"bytes_resp_B\\": %B, \\"bytes_tx_O\\": %O, \\"bytes_rx_I\\": %I, \\"bytes_rx_tx_S\\": %S }" issue_203
CustomLog logs/test_004_30 issue_203
        """).add_vhost_cgi().install()
        assert TestEnv.apache_restart() == 0
        url = TestEnv.mkurl("https", "cgi", "/files/{0}".format(resource))
        r = TestEnv.curl_get(url, 5, ["--http2"])
        assert 200 == r["response"]["status"]
        r = TestEnv.curl_get(
            url, 5,
            ["--http1.1", "-H", "Range: bytes=0-{0}".format(chunk - 1)])
        assert 206 == r["response"]["status"]
        assert chunk == len(r["response"]["body"].decode('utf-8'))
        r = TestEnv.curl_get(
            url, 5, ["--http2", "-H", "Range: bytes=0-{0}".format(chunk - 1)])
        assert 206 == r["response"]["status"]
        assert chunk == len(r["response"]["body"].decode('utf-8'))
        # now check what response lengths have actually been reported
        lines = open(logfile).readlines()
        log_h2_full = json.loads(lines[-3])
        log_h1 = json.loads(lines[-2])
        log_h2 = json.loads(lines[-1])
        assert log_h2_full['bytes_rx_I'] > 0
        assert log_h2_full['bytes_resp_B'] == full_length
        assert log_h2_full['bytes_tx_O'] > full_length
        assert log_h1['bytes_rx_I'] > 0  # input bytes recieved
        assert log_h1['bytes_resp_B'] == chunk  # response bytes sent (payload)
        assert log_h1['bytes_tx_O'] > chunk  # output bytes sent
        assert log_h2['bytes_rx_I'] > 0
        assert log_h2['bytes_resp_B'] == chunk
        assert log_h2['bytes_tx_O'] > chunk

    def test_004_40(self):
        # echo content using h2test_module "echo" handler
        def post_and_verify(fname, options=None):
            url = TestEnv.mkurl("https", "cgi", "/h2test/echo")
            fpath = os.path.join(TestEnv.GEN_DIR, fname)
            r = TestEnv.curl_upload(url, fpath, options=options)
            assert r["rv"] == 0
            assert r["response"]["status"] >= 200 and r["response"][
                "status"] < 300

            ct = r["response"]["header"]["content-type"]
            mail_hd = "Content-Type: " + ct + "\r\nMIME-Version: 1.0\r\n\r\n"
            mime_msg = mail_hd.encode() + r["response"]["body"]
            # this MIME API is from hell
            body = email.parser.BytesParser().parsebytes(mime_msg)
            assert body
            assert body.is_multipart()
            filepart = None
            for part in body.walk():
                if fname == part.get_filename():
                    filepart = part
            assert filepart
            with open(TestEnv.e2e_src(fpath), mode='rb') as file:
                src = file.read()
            assert src == filepart.get_payload(decode=True)

        post_and_verify("data-1k", [])
예제 #44
0
 def test_310_301(self):
     TestEnv.a2md([
         "add", "testdomain.org", "www.testdomain.org",
         "mail.testdomain.org", "mail.testdomain2.org"
     ])
     TestEnv.a2md(["add", "testdomain2.org", "www.testdomain2.org"])
     TestEnv.check_md([
         "testdomain.org", "www.testdomain.org", "mail.testdomain.org",
         "mail.testdomain2.org"
     ],
                      state=1)
     TestEnv.check_md(["testdomain2.org", "www.testdomain2.org"], state=1)
     HttpdConf(text="""
         MDomain testdomain.org www.testdomain.org mail.testdomain.org
         MDomain testdomain2.org www.testdomain2.org mail.testdomain2.org
         """).install()
     assert TestEnv.apache_restart() == 0
     TestEnv.check_md(
         ["testdomain.org", "www.testdomain.org", "mail.testdomain.org"],
         state=1)
     TestEnv.check_md(
         ["testdomain2.org", "www.testdomain2.org", "mail.testdomain2.org"],
         state=1)
예제 #45
0
def teardown_module(module):
    print("teardown_module: %s" % module.__name__)
    assert TestEnv.apache_stop() == 0
예제 #46
0
 def test_102_02(self):
     url = TestEnv.mkurl("https", "ssl", "/noh2.html")
     r = TestEnv.curl_get(url)
     assert 0 == r["rv"]
     assert "response" in r
     assert 403 == r["response"]["status"]
예제 #47
0
def setup_module(module):
    print("setup_module: %s" % module.__name__)
    TestEnv.init()
    HttpdConf().add_vhost_cgi().install()
    assert TestEnv.apache_restart() == 0
예제 #48
0
 def test_310_109(self):
     HttpdConf(text="""
         MDomain testdomain.org www.testdomain.org mail.testdomain.org
         """).install()
     assert TestEnv.apache_restart() == 0
     assert TestEnv.a2md(["list"])['jout']['output'][0]['renew-mode'] == 1
예제 #49
0
 def test_300_01(self):
     url = TestEnv.mkurl("https", "test1", "/index.html")
     r = TestEnv.curl_post_data(url, 'XYZ')
     assert 200 == r["response"]["status"]
     assert not "previous" in r["response"]
예제 #50
0
 def test_702_031(self):
     domain = self.test_domain
     nameX = "test-x." + domain
     nameA = "test-a." + domain
     nameB = "test-b." + domain
     nameC = "test-c." + domain
     domains = [nameX, nameA, nameB]
     #
     # generate 1 MD and 2 vhosts
     conf = HttpdConf()
     conf.add_admin("admin@" + domain)
     conf.add_md(domains)
     conf.add_vhost(nameA)
     conf.add_vhost(nameB)
     conf.install()
     #
     # restart (-> drive), check that MD was synched and completes
     assert TestEnv.apache_restart() == 0
     TestEnv.check_md(domains)
     assert TestEnv.await_completion([nameX])
     TestEnv.check_md_complete(nameX)
     #
     # check: SSL is running OK
     certA = TestEnv.get_cert(nameA)
     assert nameA in certA.get_san_list()
     certB = TestEnv.get_cert(nameB)
     assert nameB in certB.get_san_list()
     assert certA.get_serial() == certB.get_serial()
     #
     # change MD by removing 1st name and adding another
     new_list = [nameA, nameB, nameC]
     conf = HttpdConf()
     conf.add_admin("admin@" + domain)
     conf.add_md(new_list)
     conf.add_vhost(nameA)
     conf.add_vhost(nameB)
     conf.install()
     # restart, check that host still works and have new cert
     assert TestEnv.apache_restart() == 0
     TestEnv.check_md(new_list)
     assert TestEnv.await_completion([nameA])
     #
     certA2 = TestEnv.get_cert(nameA)
     assert nameA in certA2.get_san_list()
     assert certA.get_serial() != certA2.get_serial()
예제 #51
0
 def test_310_001(self):
     HttpdConf(text="").install()
     assert TestEnv.apache_restart() == 0
     jout = TestEnv.a2md(["list"])['jout']
     assert 0 == len(jout["output"])
예제 #52
0
 def install(self):
     TestEnv.install_test_conf(self.path)
예제 #53
0
 def test_702_032(self):
     domain = self.test_domain
     name1 = "server1." + domain
     name2 = "server2.b" + domain  # need a separate TLD to avoid rate limites
     #
     # generate 2 MDs and 2 vhosts
     conf = HttpdConf()
     conf.add_admin("admin@" + domain)
     conf._add_line("MDMembers auto")
     conf.add_md([name1])
     conf.add_md([name2])
     conf.add_vhost(name1)
     conf.add_vhost(name2)
     conf.install()
     #
     # restart (-> drive), check that MD was synched and completes
     assert TestEnv.apache_restart() == 0
     TestEnv.check_md([name1])
     TestEnv.check_md([name2])
     assert TestEnv.await_completion([name1, name2])
     TestEnv.check_md_complete(name2)
     #
     # check: SSL is running OK
     cert1 = TestEnv.get_cert(name1)
     assert name1 in cert1.get_san_list()
     cert2 = TestEnv.get_cert(name2)
     assert name2 in cert2.get_san_list()
     #
     # remove second md and vhost, add name2 to vhost1
     conf = HttpdConf()
     conf.add_admin("admin@" + domain)
     conf._add_line("MDMembers auto")
     conf.add_md([name1])
     conf.add_vhost([name1, name2])
     conf.install()
     assert TestEnv.apache_restart() == 0
     TestEnv.check_md([name1, name2])
     assert TestEnv.await_completion([name1])
     #
     cert1b = TestEnv.get_cert(name1)
     assert name1 in cert1b.get_san_list()
     assert name2 in cert1b.get_san_list()
     assert cert1.get_serial() != cert1b.get_serial()