1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3#*************************************************************************** 4# _ _ ____ _ 5# Project ___| | | | _ \| | 6# / __| | | | |_) | | 7# | (__| |_| | _ <| |___ 8# \___|\___/|_| \_\_____| 9# 10# Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 11# 12# This software is licensed as described in the file COPYING, which 13# you should have received as part of this distribution. The terms 14# are also available at https://curl.se/docs/copyright.html. 15# 16# You may opt to use, copy, modify, merge, publish, distribute and/or sell 17# copies of the Software, and permit persons to whom the Software is 18# furnished to do so, under the terms of the COPYING file. 19# 20# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 21# KIND, either express or implied. 22# 23# SPDX-License-Identifier: curl 24# 25########################################################################### 26# 27import json 28import logging 29from typing import Optional, Tuple, List, Dict 30import pytest 31 32from testenv import Env, CurlClient, ExecResult 33 34 35log = logging.getLogger(__name__) 36 37 38class TestEyeballs: 39 40 @pytest.fixture(autouse=True, scope='class') 41 def _class_scope(self, env, httpd, nghttpx): 42 if env.have_h3(): 43 nghttpx.start_if_needed() 44 httpd.clear_extra_configs() 45 httpd.reload() 46 47 # download using only HTTP/3 on working server 48 @pytest.mark.skipif(condition=not Env.have_h3(), reason=f"missing HTTP/3 support") 49 def test_06_01_h3_only(self, env: Env, httpd, nghttpx, repeat): 50 curl = CurlClient(env=env) 51 urln = f'https://{env.authority_for(env.domain1, "h3")}/data.json' 52 r = curl.http_download(urls=[urln], extra_args=['--http3-only']) 53 r.check_response(count=1, http_status=200) 54 assert r.stats[0]['http_version'] == '3' 55 56 # download using only HTTP/3 on missing server 57 @pytest.mark.skipif(condition=not Env.have_h3(), reason=f"missing HTTP/3 support") 58 def test_06_02_h3_only(self, env: Env, httpd, nghttpx, repeat): 59 nghttpx.stop_if_running() 60 curl = CurlClient(env=env) 61 urln = f'https://{env.authority_for(env.domain1, "h3")}/data.json' 62 r = curl.http_download(urls=[urln], extra_args=['--http3-only']) 63 r.check_response(exitcode=7, http_status=None) 64 65 # download using HTTP/3 on missing server with fallback on h2 66 @pytest.mark.skipif(condition=not Env.have_h3(), reason=f"missing HTTP/3 support") 67 def test_06_03_h3_fallback_h2(self, env: Env, httpd, nghttpx, repeat): 68 nghttpx.stop_if_running() 69 curl = CurlClient(env=env) 70 urln = f'https://{env.authority_for(env.domain1, "h3")}/data.json' 71 r = curl.http_download(urls=[urln], extra_args=['--http3']) 72 r.check_response(count=1, http_status=200) 73 assert r.stats[0]['http_version'] == '2' 74 75 # download using HTTP/3 on missing server with fallback on http/1.1 76 @pytest.mark.skipif(condition=not Env.have_h3(), reason=f"missing HTTP/3 support") 77 def test_06_04_h3_fallback_h1(self, env: Env, httpd, nghttpx, repeat): 78 nghttpx.stop_if_running() 79 curl = CurlClient(env=env) 80 urln = f'https://{env.authority_for(env.domain2, "h3")}/data.json' 81 r = curl.http_download(urls=[urln], extra_args=['--http3']) 82 r.check_response(count=1, http_status=200) 83 assert r.stats[0]['http_version'] == '1.1' 84 85 # make a successful https: transfer and observer the timer stats 86 def test_06_10_stats_success(self, env: Env, httpd, nghttpx, repeat): 87 curl = CurlClient(env=env) 88 urln = f'https://{env.authority_for(env.domain1, "h2")}/data.json' 89 r = curl.http_download(urls=[urln]) 90 r.check_response(count=1, http_status=200) 91 assert r.stats[0]['time_connect'] > 0.0 92 assert r.stats[0]['time_appconnect'] > 0.0 93 94 # make https: to a hostname that tcp connects, but will not verify 95 def test_06_11_stats_fail_verify(self, env: Env, httpd, nghttpx, repeat): 96 curl = CurlClient(env=env) 97 urln = f'https://not-valid.com:{env.https_port}/data.json' 98 r = curl.http_download(urls=[urln], extra_args=[ 99 '--resolve', f'not-valid.com:{env.https_port}:127.0.0.1' 100 ]) 101 r.check_response(count=1, http_status=0, exitcode=False) 102 assert r.stats[0]['time_connect'] > 0.0 # was tcp connected 103 assert r.stats[0]['time_appconnect'] == 0 # but not SSL verified 104 105 # make https: to an invalid address 106 def test_06_12_stats_fail_tcp(self, env: Env, httpd, nghttpx, repeat): 107 curl = CurlClient(env=env) 108 urln = f'https://not-valid.com:1/data.json' 109 r = curl.http_download(urls=[urln], extra_args=[ 110 '--resolve', f'not-valid.com:{1}:127.0.0.1' 111 ]) 112 r.check_response(count=1, http_status=None, exitcode=False) 113 assert r.stats[0]['time_connect'] == 0 # no one should have listened 114 assert r.stats[0]['time_appconnect'] == 0 # did not happen either 115