# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0.
import filecmp
import subprocess
import sys
import urllib.request
import unittest
import os.path

TIMEOUT = 300

# Accepting multiple args so we can pass something like: python elasticurl.py
elasticurl_cmd_prefix = sys.argv[1:]
if not elasticurl_cmd_prefix:
    print('You must pass the elasticurl cmd prefix')
    sys.exit(-1)

program_to_run = elasticurl_cmd_prefix[0]

if 'bin' in program_to_run:
    if not os.path.exists(program_to_run):
        print('the program_to_run is not found, skip integration test')
        sys.exit(0)

# Remove args from sys.argv so that unittest doesn't also try to parse them.
sys.argv = sys.argv[:1]

def run_command(args):
    # gather all stderr and stdout to a single string that we print only if things go wrong
    process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    timedout = False
    try:
        output = process.communicate(timeout=TIMEOUT)[0]
    except subprocess.TimeoutExpired:
        timedout = True
        process.kill()
        args_str = subprocess.list2cmdline(args)
        output = process.communicate()[0]
    finally:
        if process.returncode != 0 or timedout:
            args_str = subprocess.list2cmdline(args)
            print(args_str)
            for line in output.splitlines():
                print(line.decode())
            if timedout:
                raise RuntimeError("Timeout happened after {secs} secs from: {cmd}".format(secs=TIMEOUT, cmd=args_str))
            else:
                raise RuntimeError("Return code {code} from: {cmd}".format(code=process.returncode, cmd=args_str))

def compare_files(filename_expected, filename_other):
    if not filecmp.cmp(filename_expected, filename_other, shallow=False):
        # Give a helpful error message
        with open(filename_expected, 'rb') as expected:
            try:
                bytes_expected = bytearray(expected.read())
            except:
                raise RuntimeError("Failed to open %s" % filename_expected)

        with open(filename_other, 'rb') as other:
            try:
                bytes_other = bytearray(other.read())
            except:
                raise RuntimeError("Failed to open %s" % filename_other)

        if len(bytes_expected) != len(bytes_other):
            raise RuntimeError("File lengths differ. Expected %d, got %d" % (len(bytes_expected), len(bytes_other)))

        for i in range(len(bytes_expected)):
            if bytes_expected[i] != bytes_other[i]:
                raise RuntimeError("Files differ at byte[%d]. Expected %d, got %d." % (i, bytes_expected[i], bytes_other[i]))

        print("filecmp says these files differ, but they are identical. what the heck.")

class SimpleTests(unittest.TestCase):
    def test_simple_get_amazon(self):
        """make a simple GET request via alpn h2;http/1.1 to amazon and make sure it succeeds"""
        simple_get_args = elasticurl_cmd_prefix + ['-v', 'TRACE', 'https://www.amazon.com']
        run_command(simple_get_args)
    def test_simple_get_google(self):
        """make a simple GET request via alpn h2;http/1.1 to google and make sure it succeeds"""
        simple_get_args = elasticurl_cmd_prefix + ['-v', 'TRACE', 'https://www.google.com']
        run_command(simple_get_args)
    def test_simple_get_h1(self):
        """make a simple GET request via HTTP/1.1 and make sure it succeeds"""
        simple_get_args = elasticurl_cmd_prefix + ['-v', 'TRACE', '--http1_1', 'http://postman-echo.com/get']
        run_command(simple_get_args)

    def test_simple_post_h1(self):
        """make a simple POST request via HTTP/1.1 to make sure sending data succeeds"""
        simple_post_args = elasticurl_cmd_prefix + ['-v', 'TRACE', '--http1_1', '-P', '-H', 'content-type: application/json', '-i', '-d', '\"{\'test\':\'testval\'}\"', 'http://postman-echo.com/post']
        run_command(simple_post_args)

    def test_simple_download_h1(self):
        """download a large file via HTTP/1.1 and compare the results with something we assume works (e.g. urllib)"""
        elasticurl_download_args = elasticurl_cmd_prefix + ['-v', 'TRACE', '--http1_1', '-o', 'elastigirl.png', 'https://s3.amazonaws.com/code-sharing-aws-crt/elastigirl.png']
        run_command(elasticurl_download_args)
        urllib.request.urlretrieve('https://s3.amazonaws.com/code-sharing-aws-crt/elastigirl.png', 'elastigirl_expected.png')

        compare_files('elastigirl_expected.png', 'elastigirl.png')

    def test_simple_get_h2(self):
        """make a simple GET request via HTTP2 and make sure it succeeds"""
        simple_get_args = elasticurl_cmd_prefix + ['-v', 'TRACE', '--http2', 'https://postman-echo.com/get']
        run_command(simple_get_args)

    def test_simple_post_h2(self):
        """make a simple POST request via HTTP2 to make sure sending data succeeds"""
        simple_post_args = elasticurl_cmd_prefix + ['-v', 'TRACE', '--http2', '-P', '-H', 'content-type: application/json', '-i', '-d', '\"{\'test\':\'testval\'}\"', 'https://postman-echo.com/post']
        run_command(simple_post_args)

    def test_simple_download_h2(self):
        """download a large file via HTTP2 and compare the results with something we assume works (e.g. urllib)"""
        elasticurl_download_args = elasticurl_cmd_prefix + ['-v', 'TRACE', '--http2', '-o', 'elastigirl_h2.png', 'https://d1cz66xoahf9cl.cloudfront.net/elastigirl.png']
        run_command(elasticurl_download_args)
        urllib.request.urlretrieve('https://d1cz66xoahf9cl.cloudfront.net/elastigirl.png', 'elastigirl_expected.png')

        compare_files('elastigirl_expected.png', 'elastigirl_h2.png')

if __name__ == '__main__':
    unittest.main(verbosity=2)
