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