xref: /aosp_15_r20/external/lz4/tests/test-lz4-abi.py (revision 27162e4e17433d5aa7cb38e7b6a433a09405fc7f)
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