17 from email
.utils
import formatdate
18 from pathlib
import Path
20 from urllib
import parse
22 import dump_trace_images
24 TRACES_DB_PATH
= "./traces-db/"
25 RESULTS_PATH
= "./results/"
26 MINIO_HOST
= "minio-packet.freedesktop.org"
27 DASHBOARD_URL
= "https://tracie.freedesktop.org/dashboard"
29 def replay(trace_path
, device_name
):
30 success
= dump_trace_images
.dump_from_trace(trace_path
, [], device_name
)
33 print("[check_image] Trace %s couldn't be replayed. See above logs for more information." % (str(trace_path
)))
34 return None, None, None
36 base_path
= trace_path
.parent
37 file_name
= trace_path
.name
38 files
= glob
.glob(str(base_path
/ "test" / device_name
/ (file_name
+ "-*" + ".png")))
41 files
= glob
.glob(str(base_path
/ "test" / device_name
/ (file_name
+ ".log")))
44 return hashlib
.md5(Image
.open(image_file
).tobytes()).hexdigest(), image_file
, log_file
46 def gitlab_ensure_trace(project_url
, trace
):
47 trace_path
= TRACES_DB_PATH
+ trace
['path']
48 if project_url
is None:
49 if not os
.path
.exists(trace_path
):
50 print("{} missing".format(trace_path
))
54 os
.makedirs(os
.path
.dirname(trace_path
), exist_ok
=True)
56 if os
.path
.exists(trace_path
):
59 print("[check_image] Downloading trace %s" % (trace
['path']), end
=" ", flush
=True)
60 download_time
= time
.time()
61 r
= requests
.get(project_url
+ trace
['path'])
62 open(trace_path
, "wb").write(r
.content
)
63 print("took %ds." % (time
.time() - download_time
), flush
=True)
65 def sign_with_hmac(key
, message
):
66 key
= key
.encode("UTF-8")
67 message
= message
.encode("UTF-8")
69 signature
= hmac
.new(key
, message
, hashlib
.sha1
).digest()
71 return base64
.encodebytes(signature
).strip().decode()
73 def upload_to_minio(file_name
, resource
, content_type
):
74 with
open('.minio_credentials', 'r') as f
:
75 credentials
= json
.load(f
)[MINIO_HOST
]
76 minio_key
= credentials
["AccessKeyId"]
77 minio_secret
= credentials
["SecretAccessKey"]
78 minio_token
= credentials
["SessionToken"]
80 date
= formatdate(timeval
=None, localtime
=False, usegmt
=True)
81 url
= 'https://%s%s' % (MINIO_HOST
, resource
)
82 to_sign
= "PUT\n\n%s\n%s\nx-amz-security-token:%s\n%s" % (content_type
, date
, minio_token
, resource
)
83 signature
= sign_with_hmac(minio_secret
, to_sign
)
85 with
open(file_name
, 'rb') as data
:
86 headers
= {'Host': MINIO_HOST
,
88 'Content-Type': content_type
,
89 'Authorization': 'AWS %s:%s' % (minio_key
, signature
),
90 'x-amz-security-token': minio_token
}
91 print("Uploading artifact to %s" % url
);
92 r
= requests
.put(url
, headers
=headers
, data
=data
)
93 if r
.status_code
>= 400:
97 def upload_artifact(file_name
, key
, content_type
):
98 resource
= '/artifacts/%s/%s/%s/%s' % (os
.environ
['CI_PROJECT_PATH'],
99 os
.environ
['CI_PIPELINE_ID'],
100 os
.environ
['CI_JOB_ID'],
102 upload_to_minio(file_name
, resource
, content_type
)
104 def ensure_reference_image(file_name
, checksum
):
105 resource
= '/mesa-tracie-results/%s/%s.png' % (os
.environ
['CI_PROJECT_PATH'], checksum
)
106 url
= 'https://%s%s' % (MINIO_HOST
, resource
)
107 r
= requests
.head(url
, allow_redirects
=True)
108 if r
.status_code
== 200:
110 upload_to_minio(file_name
, resource
, 'image/png')
112 def gitlab_check_trace(project_url
, device_name
, trace
, expectation
):
113 gitlab_ensure_trace(project_url
, trace
)
116 result
[trace
['path']] = {}
117 result
[trace
['path']]['expected'] = expectation
['checksum']
119 trace_path
= Path(TRACES_DB_PATH
+ trace
['path'])
120 checksum
, image_file
, log_file
= replay(trace_path
, device_name
)
122 result
[trace
['path']]['actual'] = 'error'
124 elif checksum
== expectation
['checksum']:
125 print("[check_image] Images match for %s" % (trace
['path']))
128 print("[check_image] Images differ for %s (expected: %s, actual: %s)" %
129 (trace
['path'], expectation
['checksum'], checksum
))
130 print("[check_image] For more information see "
131 "https://gitlab.freedesktop.org/mesa/mesa/blob/master/.gitlab-ci/tracie/README.md")
132 image_diff_url
= "%s/imagediff/%s/%s/%s/%s/%s" % (DASHBOARD_URL
,
133 os
.environ
['CI_PROJECT_PATH'],
134 os
.environ
['CI_PIPELINE_ID'],
135 os
.environ
['CI_JOB_ID'],
136 expectation
['checksum'],
138 print("[check_image] %s" % image_diff_url
)
141 trace_dir
= os
.path
.split(trace
['path'])[0]
142 dir_in_results
= os
.path
.join(trace_dir
, "test", device_name
)
143 results_path
= os
.path
.join(RESULTS_PATH
, dir_in_results
)
144 os
.makedirs(results_path
, exist_ok
=True)
145 shutil
.move(log_file
, os
.path
.join(results_path
, os
.path
.split(log_file
)[1]))
146 if os
.environ
.get('TRACIE_UPLOAD_TO_MINIO', '0') == '1':
148 if os
.environ
['CI_PROJECT_PATH'] == 'mesa/mesa':
149 ensure_reference_image(image_file
, checksum
)
151 upload_artifact(image_file
, 'traces/%s.png' % checksum
, 'image/png')
152 if not ok
or os
.environ
.get('TRACIE_STORE_IMAGES', '0') == '1':
153 image_name
= os
.path
.split(image_file
)[1]
154 shutil
.move(image_file
, os
.path
.join(results_path
, image_name
))
155 result
[trace
['path']]['image'] = os
.path
.join(dir_in_results
, image_name
)
157 result
[trace
['path']]['actual'] = checksum
161 def run(filename
, device_name
):
163 with
open(filename
, 'r') as f
:
164 y
= yaml
.safe_load(f
)
167 project_url
= y
["traces-db"]["download-url"]
171 traces
= y
['traces'] or []
175 for expectation
in trace
['expectations']:
176 if expectation
['device'] == device_name
:
177 ok
, result
= gitlab_check_trace(project_url
,
180 all_ok
= all_ok
and ok
181 results
.update(result
)
183 os
.makedirs(RESULTS_PATH
, exist_ok
=True)
184 with
open(os
.path
.join(RESULTS_PATH
, 'results.yml'), 'w') as f
:
185 yaml
.safe_dump(results
, f
, default_flow_style
=False)
186 if os
.environ
.get('TRACIE_UPLOAD_TO_MINIO', '0') == '1':
187 upload_artifact(os
.path
.join(RESULTS_PATH
, 'results.yml'), 'traces/results.yml', 'text/yaml')
192 parser
= argparse
.ArgumentParser()
193 parser
.add_argument('--file', required
=True,
194 help='the name of the traces.yml file listing traces and their checksums for each device')
195 parser
.add_argument('--device-name', required
=True,
196 help="the name of the graphics device used to replay traces")
198 args
= parser
.parse_args(args
)
199 return run(args
.file, args
.device_name
)
201 if __name__
== "__main__":
202 all_ok
= main(sys
.argv
[1:])
203 sys
.exit(0 if all_ok
else 1)