xref: /curl/tests/http/testenv/client.py (revision a3601cf5)
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 logging
28import os
29import shutil
30import subprocess
31from datetime import datetime
32from typing import Optional, Dict
33
34from . import ExecResult
35from .env import Env
36
37
38log = logging.getLogger(__name__)
39
40
41class LocalClient:
42
43    def __init__(self, name: str, env: Env, run_dir: Optional[str] = None,
44                 timeout: Optional[float] = None,
45                 run_env: Optional[Dict[str,str]] = None):
46        self.name = name
47        self.path = os.path.join(env.build_dir, f'tests/http/clients/{name}')
48        self.env = env
49        self._run_env = run_env
50        self._timeout = timeout if timeout else env.test_timeout
51        self._curl = os.environ['CURL'] if 'CURL' in os.environ else env.curl
52        self._run_dir = run_dir if run_dir else os.path.join(env.gen_dir, name)
53        self._stdoutfile = f'{self._run_dir}/stdout'
54        self._stderrfile = f'{self._run_dir}/stderr'
55        self._rmrf(self._run_dir)
56        self._mkpath(self._run_dir)
57
58    @property
59    def run_dir(self) -> str:
60        return self._run_dir
61
62    @property
63    def stderr_file(self) -> str:
64        return self._stderrfile
65
66    def exists(self) -> bool:
67        return os.path.exists(self.path)
68
69    def download_file(self, i: int) -> str:
70        return os.path.join(self._run_dir, f'download_{i}.data')
71
72    def _rmf(self, path):
73        if os.path.exists(path):
74            return os.remove(path)
75
76    def _rmrf(self, path):
77        if os.path.exists(path):
78            return shutil.rmtree(path)
79
80    def _mkpath(self, path):
81        if not os.path.exists(path):
82            return os.makedirs(path)
83
84    def run(self, args):
85        self._rmf(self._stdoutfile)
86        self._rmf(self._stderrfile)
87        start = datetime.now()
88        exception = None
89        myargs = [self.path]
90        myargs.extend(args)
91        run_env = None
92        if self._run_env:
93            run_env = self._run_env.copy()
94            for key in ['CURL_DEBUG']:
95                if key in os.environ and key not in run_env:
96                    run_env[key] = os.environ[key]
97        try:
98            with open(self._stdoutfile, 'w') as cout, open(self._stderrfile, 'w') as cerr:
99                p = subprocess.run(myargs, stderr=cerr, stdout=cout,
100                                   cwd=self._run_dir, shell=False,
101                                   input=None, env=run_env,
102                                   timeout=self._timeout)
103                exitcode = p.returncode
104        except subprocess.TimeoutExpired:
105            log.warning(f'Timeout after {self._timeout}s: {args}')
106            exitcode = -1
107            exception = 'TimeoutExpired'
108        coutput = open(self._stdoutfile).readlines()
109        cerrput = open(self._stderrfile).readlines()
110        return ExecResult(args=myargs, exit_code=exitcode, exception=exception,
111                          stdout=coutput, stderr=cerrput,
112                          duration=datetime.now() - start)
113
114    def dump_logs(self):
115        lines = []
116        lines.append('>>--stdout ----------------------------------------------\n')
117        lines.extend(open(self._stdoutfile).readlines())
118        lines.append('>>--stderr ----------------------------------------------\n')
119        lines.extend(open(self._stderrfile).readlines())
120        lines.append('<<-------------------------------------------------------\n')
121        return ''.join(lines)
122