1*27162e4eSAndroid Build Coastguard Worker#!/usr/bin/env python3 2*27162e4eSAndroid Build Coastguard Worker"""Test LZ4 interoperability between versions""" 3*27162e4eSAndroid Build Coastguard Worker 4*27162e4eSAndroid Build Coastguard Worker# 5*27162e4eSAndroid Build Coastguard Worker# Copyright (C) 2011-present, Takayuki Matsuoka 6*27162e4eSAndroid Build Coastguard Worker# All rights reserved. 7*27162e4eSAndroid Build Coastguard Worker# GPL v2 License 8*27162e4eSAndroid Build Coastguard Worker# 9*27162e4eSAndroid Build Coastguard Worker 10*27162e4eSAndroid Build Coastguard Workerimport argparse 11*27162e4eSAndroid Build Coastguard Workerimport glob 12*27162e4eSAndroid Build Coastguard Workerimport subprocess 13*27162e4eSAndroid Build Coastguard Workerimport filecmp 14*27162e4eSAndroid Build Coastguard Workerimport os 15*27162e4eSAndroid Build Coastguard Workerimport shutil 16*27162e4eSAndroid Build Coastguard Workerimport sys 17*27162e4eSAndroid Build Coastguard Workerimport hashlib 18*27162e4eSAndroid Build Coastguard Worker 19*27162e4eSAndroid Build Coastguard Workerrepo_url = 'https://github.com/lz4/lz4.git' 20*27162e4eSAndroid Build Coastguard Workertmp_dir_name = 'tests/abiTests' 21*27162e4eSAndroid Build Coastguard Workerenv_flags = ' ' # '-j CFLAGS="-g -O0 -fsanitize=address"' 22*27162e4eSAndroid Build Coastguard Workermake_cmd = 'make' 23*27162e4eSAndroid Build Coastguard Workergit_cmd = 'git' 24*27162e4eSAndroid Build Coastguard Workertest_dat_src = ['README.md'] 25*27162e4eSAndroid Build Coastguard Workerhead = 'v999' 26*27162e4eSAndroid Build Coastguard Worker 27*27162e4eSAndroid Build Coastguard Workerparser = argparse.ArgumentParser() 28*27162e4eSAndroid Build Coastguard Workerparser.add_argument("--verbose", action="store_true", help="increase output verbosity") 29*27162e4eSAndroid Build Coastguard Workerargs = parser.parse_args() 30*27162e4eSAndroid Build Coastguard Worker 31*27162e4eSAndroid Build Coastguard Workerdef debug_message(msg): 32*27162e4eSAndroid Build Coastguard Worker if args.verbose: 33*27162e4eSAndroid Build Coastguard Worker print(msg) 34*27162e4eSAndroid Build Coastguard Worker 35*27162e4eSAndroid Build Coastguard Workerdef proc(cmd_args, pipe=True, env=False): 36*27162e4eSAndroid Build Coastguard Worker if env == False: 37*27162e4eSAndroid Build Coastguard Worker env = os.environ.copy() 38*27162e4eSAndroid Build Coastguard Worker debug_message("Executing command {} with env {}".format(cmd_args, env)) 39*27162e4eSAndroid Build Coastguard Worker if pipe: 40*27162e4eSAndroid Build Coastguard Worker s = subprocess.Popen(cmd_args, 41*27162e4eSAndroid Build Coastguard Worker stdout=subprocess.PIPE, 42*27162e4eSAndroid Build Coastguard Worker stderr=subprocess.PIPE, 43*27162e4eSAndroid Build Coastguard Worker env = env) 44*27162e4eSAndroid Build Coastguard Worker else: 45*27162e4eSAndroid Build Coastguard Worker s = subprocess.Popen(cmd_args, env = env) 46*27162e4eSAndroid Build Coastguard Worker stdout_data, stderr_data = s.communicate() 47*27162e4eSAndroid Build Coastguard Worker if s.poll() != 0: 48*27162e4eSAndroid Build Coastguard Worker print('Error Code:', s.poll()) 49*27162e4eSAndroid Build Coastguard Worker print('Standard Error:', stderr_data.decode()) 50*27162e4eSAndroid Build Coastguard Worker sys.exit(1) 51*27162e4eSAndroid Build Coastguard Worker return stdout_data, stderr_data 52*27162e4eSAndroid Build Coastguard Worker 53*27162e4eSAndroid Build Coastguard Workerdef make(args, pipe=True, env=False): 54*27162e4eSAndroid Build Coastguard Worker if env == False: 55*27162e4eSAndroid Build Coastguard Worker env = os.environ.copy() 56*27162e4eSAndroid Build Coastguard Worker # we want the address sanitizer for abi tests 57*27162e4eSAndroid Build Coastguard Worker if 'CFLAGS' in env: 58*27162e4eSAndroid Build Coastguard Worker env["CFLAGS"] += " -fsanitize=address" 59*27162e4eSAndroid Build Coastguard Worker if 'LDFLAGS' in env: 60*27162e4eSAndroid Build Coastguard Worker env["LDFLAGS"] += " -fsanitize=address" 61*27162e4eSAndroid Build Coastguard Worker return proc([make_cmd] + ['-j'] + ['V=1'] + ['DEBUGFLAGS='] + args, pipe, env) 62*27162e4eSAndroid Build Coastguard Worker 63*27162e4eSAndroid Build Coastguard Workerdef git(args, pipe=True): 64*27162e4eSAndroid Build Coastguard Worker return proc([git_cmd] + args, pipe) 65*27162e4eSAndroid Build Coastguard Worker 66*27162e4eSAndroid Build Coastguard Workerdef get_git_tags(): 67*27162e4eSAndroid Build Coastguard Worker # Only start from first v1.7.x format release 68*27162e4eSAndroid Build Coastguard Worker stdout, stderr = git(['tag', '-l', 'v[1-9].[0-9].[0-9]']) 69*27162e4eSAndroid Build Coastguard Worker tags = stdout.decode('utf-8').split() 70*27162e4eSAndroid Build Coastguard Worker return tags 71*27162e4eSAndroid Build Coastguard Worker 72*27162e4eSAndroid Build Coastguard Worker# https://stackoverflow.com/a/19711609/2132223 73*27162e4eSAndroid Build Coastguard Workerdef sha1_of_file(filepath): 74*27162e4eSAndroid Build Coastguard Worker with open(filepath, 'rb') as f: 75*27162e4eSAndroid Build Coastguard Worker return hashlib.sha1(f.read()).hexdigest() 76*27162e4eSAndroid Build Coastguard Worker 77*27162e4eSAndroid Build Coastguard Workerif __name__ == '__main__': 78*27162e4eSAndroid Build Coastguard Worker if sys.platform == "darwin": 79*27162e4eSAndroid Build Coastguard Worker print("!!! Warning: this test is not validated for macos !!!") 80*27162e4eSAndroid Build Coastguard Worker 81*27162e4eSAndroid Build Coastguard Worker error_code = 0 82*27162e4eSAndroid Build Coastguard Worker base_dir = os.getcwd() + '/..' # /path/to/lz4 83*27162e4eSAndroid Build Coastguard Worker tmp_dir = base_dir + '/' + tmp_dir_name # /path/to/lz4/tests/versionsTest 84*27162e4eSAndroid Build Coastguard Worker clone_dir = tmp_dir + '/' + 'lz4' # /path/to/lz4/tests/versionsTest/lz4 85*27162e4eSAndroid Build Coastguard Worker lib_dir = base_dir + '/lib' # /path/to/lz4/lib 86*27162e4eSAndroid Build Coastguard Worker test_dir = base_dir + '/tests' 87*27162e4eSAndroid Build Coastguard Worker os.makedirs(tmp_dir, exist_ok=True) 88*27162e4eSAndroid Build Coastguard Worker 89*27162e4eSAndroid Build Coastguard Worker # since Travis clones limited depth, we should clone full repository 90*27162e4eSAndroid Build Coastguard Worker if not os.path.isdir(clone_dir): 91*27162e4eSAndroid Build Coastguard Worker git(['clone', repo_url, clone_dir]) 92*27162e4eSAndroid Build Coastguard Worker 93*27162e4eSAndroid Build Coastguard Worker # Retrieve all release tags 94*27162e4eSAndroid Build Coastguard Worker print('Retrieve release tags >= v1.7.5 :') 95*27162e4eSAndroid Build Coastguard Worker os.chdir(clone_dir) 96*27162e4eSAndroid Build Coastguard Worker tags = [head] + get_git_tags() 97*27162e4eSAndroid Build Coastguard Worker tags = [x for x in tags if (x >= 'v1.7.5')] 98*27162e4eSAndroid Build Coastguard Worker print(tags) 99*27162e4eSAndroid Build Coastguard Worker 100*27162e4eSAndroid Build Coastguard Worker # loop across architectures 101*27162e4eSAndroid Build Coastguard Worker # note : '-mx32' was removed, because some CI environment (GA) do not support x32 well 102*27162e4eSAndroid Build Coastguard Worker for march in ['-m64', '-m32']: 103*27162e4eSAndroid Build Coastguard Worker print(' ') 104*27162e4eSAndroid Build Coastguard Worker print('=====================================') 105*27162e4eSAndroid Build Coastguard Worker print('Testing architecture ' + march); 106*27162e4eSAndroid Build Coastguard Worker print('=====================================') 107*27162e4eSAndroid Build Coastguard Worker 108*27162e4eSAndroid Build Coastguard Worker # Build all versions of liblz4 109*27162e4eSAndroid Build Coastguard Worker # note : naming scheme only works on Linux 110*27162e4eSAndroid Build Coastguard Worker for tag in tags: 111*27162e4eSAndroid Build Coastguard Worker print('building library ', tag) 112*27162e4eSAndroid Build Coastguard Worker os.chdir(base_dir) 113*27162e4eSAndroid Build Coastguard Worker # if not os.path.isfile(dst_liblz4) or tag == head: 114*27162e4eSAndroid Build Coastguard Worker if tag != head: 115*27162e4eSAndroid Build Coastguard Worker r_dir = '{}/{}'.format(tmp_dir, tag) # /path/to/lz4/test/lz4test/<TAG> 116*27162e4eSAndroid Build Coastguard Worker #print('r_dir = ', r_dir) # for debug 117*27162e4eSAndroid Build Coastguard Worker os.makedirs(r_dir, exist_ok=True) 118*27162e4eSAndroid Build Coastguard Worker os.chdir(clone_dir) 119*27162e4eSAndroid Build Coastguard Worker git(['--work-tree=' + r_dir, 'checkout', tag, '--', '.']) 120*27162e4eSAndroid Build Coastguard Worker os.chdir(r_dir + '/lib') # /path/to/lz4/lz4test/<TAG>/lib 121*27162e4eSAndroid Build Coastguard Worker else: 122*27162e4eSAndroid Build Coastguard Worker # print('lib_dir = {}', lib_dir) # for debug 123*27162e4eSAndroid Build Coastguard Worker os.chdir(lib_dir) 124*27162e4eSAndroid Build Coastguard Worker make(['clean']) 125*27162e4eSAndroid Build Coastguard Worker build_env = os.environ.copy() 126*27162e4eSAndroid Build Coastguard Worker build_env["CFLAGS"] = "-O1 " + march 127*27162e4eSAndroid Build Coastguard Worker make(['liblz4'], env=build_env) 128*27162e4eSAndroid Build Coastguard Worker 129*27162e4eSAndroid Build Coastguard Worker print(' ') 130*27162e4eSAndroid Build Coastguard Worker print('******************************') 131*27162e4eSAndroid Build Coastguard Worker print('Round trip expecting current ABI but linking to older Dynamic Library version') 132*27162e4eSAndroid Build Coastguard Worker print('******************************') 133*27162e4eSAndroid Build Coastguard Worker os.chdir(test_dir) 134*27162e4eSAndroid Build Coastguard Worker # Start with matching version : should be no problem 135*27162e4eSAndroid Build Coastguard Worker build_env = os.environ.copy() 136*27162e4eSAndroid Build Coastguard Worker # we use asan to detect any out-of-bound read or write 137*27162e4eSAndroid Build Coastguard Worker build_env["CFLAGS"] = "-O1 " + march 138*27162e4eSAndroid Build Coastguard Worker build_env["LDFLAGS"] = "-L../lib" 139*27162e4eSAndroid Build Coastguard Worker build_env["LDLIBS"] = "-llz4" 140*27162e4eSAndroid Build Coastguard Worker if os.path.isfile('abiTest'): 141*27162e4eSAndroid Build Coastguard Worker os.remove('abiTest') 142*27162e4eSAndroid Build Coastguard Worker make(['abiTest'], env=build_env, pipe=False) 143*27162e4eSAndroid Build Coastguard Worker 144*27162e4eSAndroid Build Coastguard Worker for tag in tags: 145*27162e4eSAndroid Build Coastguard Worker print('linking to lib tag = ', tag) 146*27162e4eSAndroid Build Coastguard Worker run_env = os.environ.copy() 147*27162e4eSAndroid Build Coastguard Worker if tag == head: 148*27162e4eSAndroid Build Coastguard Worker run_env["LD_LIBRARY_PATH"] = '../lib' 149*27162e4eSAndroid Build Coastguard Worker else: 150*27162e4eSAndroid Build Coastguard Worker run_env["LD_LIBRARY_PATH"] = 'abiTests/{}/lib'.format(tag) 151*27162e4eSAndroid Build Coastguard Worker # check we are linking to the right library version at run time 152*27162e4eSAndroid Build Coastguard Worker proc(['./check_liblz4_version.sh'] + ['./abiTest'], pipe=False, env=run_env) 153*27162e4eSAndroid Build Coastguard Worker # now run with mismatched library version 154*27162e4eSAndroid Build Coastguard Worker proc(['./abiTest'] + test_dat_src, pipe=False, env=run_env) 155*27162e4eSAndroid Build Coastguard Worker 156*27162e4eSAndroid Build Coastguard Worker print(' ') 157*27162e4eSAndroid Build Coastguard Worker print('******************************') 158*27162e4eSAndroid Build Coastguard Worker print('Round trip using current Dynamic Library expecting older ABI version') 159*27162e4eSAndroid Build Coastguard Worker print('******************************') 160*27162e4eSAndroid Build Coastguard Worker 161*27162e4eSAndroid Build Coastguard Worker for tag in tags: 162*27162e4eSAndroid Build Coastguard Worker print(' ') 163*27162e4eSAndroid Build Coastguard Worker print('building using older lib ', tag) 164*27162e4eSAndroid Build Coastguard Worker build_env = os.environ.copy() 165*27162e4eSAndroid Build Coastguard Worker if tag != head: 166*27162e4eSAndroid Build Coastguard Worker build_env["CPPFLAGS"] = '-IabiTests/{}/lib'.format(tag) 167*27162e4eSAndroid Build Coastguard Worker build_env["LDFLAGS"] = '-LabiTests/{}/lib'.format(tag) 168*27162e4eSAndroid Build Coastguard Worker else: 169*27162e4eSAndroid Build Coastguard Worker build_env["CPPFLAGS"] = '-I../lib' 170*27162e4eSAndroid Build Coastguard Worker build_env["LDFLAGS"] = '-L../lib' 171*27162e4eSAndroid Build Coastguard Worker build_env["LDLIBS"] = "-llz4" 172*27162e4eSAndroid Build Coastguard Worker build_env["CFLAGS"] = "-O1 " + march 173*27162e4eSAndroid Build Coastguard Worker os.remove('abiTest') 174*27162e4eSAndroid Build Coastguard Worker make(['abiTest'], pipe=False, env=build_env) 175*27162e4eSAndroid Build Coastguard Worker 176*27162e4eSAndroid Build Coastguard Worker print('run with CURRENT library version (head)') 177*27162e4eSAndroid Build Coastguard Worker run_env = os.environ.copy() 178*27162e4eSAndroid Build Coastguard Worker run_env["LD_LIBRARY_PATH"] = '../lib' 179*27162e4eSAndroid Build Coastguard Worker # check we are linking to the right library version at run time 180*27162e4eSAndroid Build Coastguard Worker proc(['./check_liblz4_version.sh'] + ['./abiTest'], pipe=False, env=run_env) 181*27162e4eSAndroid Build Coastguard Worker # now run with mismatched library version 182*27162e4eSAndroid Build Coastguard Worker proc(['./abiTest'] + test_dat_src, pipe=False, env=run_env) 183*27162e4eSAndroid Build Coastguard Worker 184*27162e4eSAndroid Build Coastguard Worker 185*27162e4eSAndroid Build Coastguard Worker if error_code != 0: 186*27162e4eSAndroid Build Coastguard Worker print('ERROR') 187*27162e4eSAndroid Build Coastguard Worker 188*27162e4eSAndroid Build Coastguard Worker sys.exit(error_code) 189