Attention une mise à jour du service Gitlab va être effectuée le mardi 30 novembre entre 17h30 et 18h00. Cette mise à jour va générer une interruption du service dont nous ne maîtrisons pas complètement la durée mais qui ne devrait pas excéder quelques minutes. Cette mise à jour intermédiaire en version 14.0.12 nous permettra de rapidement pouvoir mettre à votre disposition une version plus récente.

Commit d9e9bebe authored by Cypres TAC's avatar Cypres TAC
Browse files

Merge branch 'feature/pyunit' into 'master'

use pyunit for integration tests and run them in CI

See merge request !21
parents d0d980f5 7c264cd5
Pipeline #232657 passed with stages
in 4 minutes
......@@ -2,9 +2,10 @@ image: maven:3.6-jdk-11
stages:
- build
- test
- deploy
build:
build-java:
stage: build
tags:
- ci
......@@ -16,8 +17,26 @@ build:
paths:
- CLEA-lib/java/target/*.jar
test:
build-c:
stage: build
tags:
- ci
image: debian:latest
before_script:
- apt-get update
- apt-get install -y -qq cmake make gcc git
script:
- cd CLEA-lib/c
- mkdir build && cd build
- cmake ..
- make
artifacts:
paths:
- CLEA-lib/c/build/test_*
- CLEA-lib/c/build/build_clea
test-java:
stage: test
tags:
- ci
script:
......@@ -27,6 +46,18 @@ test:
paths:
- CLEA-lib/java/target/*.jar
test-interop:
stage: test
tags:
- ci
image: python:3-buster
before_script:
- apt-get update
- apt-get install -y -qq openjdk-11-jre
script:
- cd CLEA-lib/test
- python test_clea.py
deploy:
stage: deploy
tags:
......
......@@ -278,7 +278,7 @@ function printBuf(name, buf) {
}
/**
* Convert a 34 bits int in a bytes array
* Convert a 64 bits int in a bytes array
*
* @param {integer} val to be converted
* @return {Uint8Array} bytes array
......@@ -295,7 +295,7 @@ function getInt64Bytes(val) {
/**
* Parse a string composed by digits ([0..9])
* to fill a bytes array storing as aset of
* to fill a bytes array storing as a set of
* 4-bit sub-fields that each contain a digit.
* padding is done by 0xF
*
......
......@@ -9,7 +9,7 @@ This Proof of Concept can be used as a basis for:
* Validate the implementation of the encryption algorithms
* Generate locationSpecific Part for specialised devices
### Dépendancies
### Dependencies
* Python 3
......@@ -26,35 +26,33 @@ The test cycle for each set is as follows:
1. encode_in.json -> [lsp_encode] -> encode_out.json (private key + lsp in base64 format)
2. encode_out.json -> [lsp_decode] -> decode_out.json
3. test ok if the parameters in `encode_in.json` encoded are identical to those decoded in `de code_out.json` at the end of the chain
3. test ok if the parameters in `encode_in.json` encoded are identical to those decoded in `decode_out.json` at the end of the chain
To launch the test cyle use `test_clea.py`:
To launch the tests use `python3 test_clea.py`:
```bash
python test_clea.py --help
usage: test_clea.py [-h] [--noencode] [--java]
optional arguments:
-h, --help show this help message and exit
--noencode test only the decoding part
--java encoding part with Java lib (C lib by default)
```
By default, the test cycle uses the C encoder (see below). The option `-java` allows to use the Java encoder.
By default, the test cycle uses the C encoder (see below). The option `--java` allows to use the Java encoder.
```shell
>python3 test_clea.py
qrcode build 1
qrcode build 2
qrcode read 1
qrcode read 2
TEST PASS: 1
TEST PASS: 2
ALL TESTS PASS
>python3 test_clea.py --csvtest
sEncode LSP 1
Encode LSP 2
Encode LSP 3
Encode LSP 4
Encode LSP 5
Decode LSP 1
Decode LSP 2
Decode LSP 3
Decode LSP 4
Decode LSP 5
.
----------------------------------------------------------------------
Ran 2 tests in 7.949s>python3 test_clea.py
```
To generate CSV files to be used by java decoding tests, run `python3 test_clea.py --csvtest`
### Javascript
For using the javacript encoder in phase 1. of the test cycle, we need to load the page `test_clea.html`, load the json file `encode_in.json` (button browse...) and save the results in `encode_out.json` (button Write).
It is now possible to test the Java decoding to check interoperability using `python3 test_clea.py --noencode`. The option allows the skip the C or java encoding performed by your web-browser.
\ No newline at end of file
It is now possible to test the Java decoding to check interoperability using `python3 test_clea.py --noencode`. The option allows the skip the C or java encoding performed by your web-browser.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright Inria 2021
#
import json
import subprocess
import os
import argparse
import unittest
import sys
CSV_LSP_TST = 'testLSPDecoding.csv'
CSV_LOC_TST = 'testLocationDecoding.csv'
CSV_TEST_FILES_GENERATION = False
class CleaEncoderInteroperabilityTestCase(unittest.TestCase):
def setUp(self):
# clean output files
self.ENC_IN = 'encode_in.json'
self.ENC_OUT = 'encode_out.json'
self.DEC_OUT = 'decode_out.json'
if os.path.exists(self.ENC_OUT):
os.remove(self.ENC_OUT)
if os.path.exists(self.DEC_OUT):
os.remove(self.DEC_OUT)
def testCEncodingAndJavaDecoding(self):
print("Running test with C encoding and Java decoding")
lsps_encode(self.ENC_IN, self.ENC_OUT, java=False)
# encode_out.json -> [lsps_decode] -> decode_out.json
lsps_decode(self.ENC_OUT, self.DEC_OUT)
# compare parameters input or generated (time, ltid) and output paramaters
lsps_cmp(self.ENC_IN, self.ENC_OUT, self.DEC_OUT, CSV_LSP_TST, CSV_LOC_TST)
def testJavaEncodingAndJavaDecoding(self):
print("Running test with Java encoding and Java decoding")
lsps_encode(self.ENC_IN, self.ENC_OUT, java=True)
# encode_out.json -> [lsps_decode] -> decode_out.json
lsps_decode(self.ENC_OUT, self.DEC_OUT)
# compare parameters input or generated (time, ltid) and output paramaters
lsps_cmp(self.ENC_IN, self.ENC_OUT, self.DEC_OUT, CSV_LSP_TST, CSV_LOC_TST)
""" Test interoperability between C/Java location Specific Part (LSP) encoding
and Java LSP decoding
"""
......@@ -29,11 +67,12 @@ def run_cmd(cmd_with_args):
-------
result as a sequence of word separated by space
"""
subpro = subprocess.Popen(cmd_with_args, stdout=subprocess.PIPE)
subpro.wait()
out = subpro.stdout.read()
with subprocess.Popen(cmd_with_args, stdout=subprocess.PIPE) as process:
process.wait()
out = process.stdout.read()
process.kill()
outs = out.decode().replace("\n", "")
outs = outs.split('=VALUES=')
results = outs[1].split(' ')
return results
......@@ -188,35 +227,20 @@ def lsp_cmp(enc_in, enc_out, dec_out):
enc_in: input dict LSP encoder
enc_out: output dict LSP encoder
dec_out: output dict LSP decoder
Return
-------
True / False
"""
testok = 0
nbtests = 10
if enc_in.get("Error") is not None or dec_out.get("Error") is not None:
return False
if enc_in['staff'] == dec_out['staff']:
testok += 1
if enc_in['CRIexp'] == dec_out['CRIexp']:
testok += 1
if enc_in['venueType'] == dec_out['venueType']:
testok += 1
if enc_in['venueCategory1'] == dec_out['venueCategory1']:
testok += 1
if enc_in['venueCategory2'] == dec_out['venueCategory2']:
testok += 1
if enc_in['countryCode'] == dec_out['countryCode']:
testok += 1
if enc_in['periodDuration'] == dec_out['periodDuration']:
testok += 1
if enc_out['LTId'] == dec_out['LTId']:
testok += 1
if enc_out['ct_periodStart'] == dec_out['ct_periodStart']:
testok += 1
if enc_out['t_qrStart'] == dec_out['t_qrStart']:
testok += 1
assert enc_in.get("Error") is None
assert dec_out.get("Error") is None
assert enc_in['staff'] == dec_out['staff']
assert enc_in['CRIexp'] == dec_out['CRIexp']
assert enc_in['venueType'] == dec_out['venueType']
assert enc_in['venueCategory1'] == dec_out['venueCategory1']
assert enc_in['venueCategory2'] == dec_out['venueCategory2']
assert enc_in['countryCode'] == dec_out['countryCode']
assert enc_in['periodDuration'] == dec_out['periodDuration']
assert enc_out['LTId'] == dec_out['LTId']
assert enc_out['ct_periodStart'] == dec_out['ct_periodStart']
assert enc_out['t_qrStart'] == dec_out['t_qrStart']
nbr = int(enc_in.get('locationPhone') is not None) + \
int(enc_in.get('locationPIN') is not None) + \
int(enc_in.get('locationRegion') is not None) + \
......@@ -224,19 +248,11 @@ def lsp_cmp(enc_in, enc_out, dec_out):
int(dec_out.get('locationRegion') is not None) + \
int(dec_out.get('locationPIN') is not None)
if nbr == 6:
nbtests += 3
if enc_in['locationPhone'] == dec_out['locationPhone']:
testok += 1
if enc_in['locationRegion'] == dec_out['locationRegion']:
testok += 1
if enc_in['locationPIN'] == dec_out['locationPIN']:
testok += 1
elif nbr != 0:
print('LocationMsg failed')
return False
return testok == nbtests
assert enc_in['locationPhone'] == dec_out['locationPhone']
assert enc_in['locationRegion'] == dec_out['locationRegion']
assert enc_in['locationPIN'] == dec_out['locationPIN']
else:
assert nbr == 0, 'LocationMsg failed'
def lsps_cmp(enc_in_file, enc_out_file, dec_out_file, csv_lsp_file, csv_loc_file):
"""
......@@ -250,9 +266,6 @@ def lsps_cmp(enc_in_file, enc_out_file, dec_out_file, csv_lsp_file, csv_loc_file
for junit5 test in ../java/src/test/resources
csv_loc_file: save location encoding/decoding results to be updated when necessary
for junit5 test in ../java/src/test/resources
Return
-------
True / False
"""
with open(enc_in_file) as fid1, \
open(enc_out_file) as fid2, \
......@@ -260,87 +273,50 @@ def lsps_cmp(enc_in_file, enc_out_file, dec_out_file, csv_lsp_file, csv_loc_file
enc_in_s = json.load(fid1)
enc_out_s = json.load(fid2)
dec_out_s = json.load(fid3)
if not len(enc_in_s) == len(enc_out_s) == len(dec_out_s):
print('TESTS FAILED: problem with number of tests')
return False
iok = 0
assert len(enc_in_s) == len(enc_out_s) == len(dec_out_s), "problem with number of tests"
for idx, _ in enumerate(enc_in_s):
enc_in = enc_in_s[idx]
enc_out = enc_out_s[idx]
dec_out = dec_out_s[idx]
if lsp_cmp(enc_in, enc_out, dec_out):
print('TEST PASS:', idx+1)
iok = iok + 1
sep = ', '
if csv_lsp_file is not None:
row = str(enc_in['staff']) + sep + str(enc_in['countryCode']) + sep
row += str(enc_out['LTId']) + sep + str(enc_in['CRIexp']) + sep
row += str(enc_in['venueType']) + sep + str(enc_in['venueCategory1']) + sep
row += str(enc_in['venueCategory2']) + sep + str(enc_in['periodDuration']) + sep
row += str(enc_out['ct_periodStart']) + sep + str(enc_out['t_qrStart']) + sep
row += str(enc_in['SK_SA']) + sep + str(enc_in['PK_SA']) + sep
row += str(enc_out['lsp_base64'])
csv_lsp_file.write(row + '\n')
if csv_loc_file is not None and enc_in.get('locationPhone') is not None:
row = str(enc_in['locationPhone']) + sep + str(enc_in['locationRegion']) + sep
row += str(enc_in['locationPIN']) + sep + str(enc_out['ct_periodStart']*3600)
row += sep + str(enc_in['SK_SA']) + sep + str(enc_in['PK_SA']) + sep
row += str(enc_in['SK_MCTA']) + sep + str(enc_in['PK_MCTA']) + sep
row += str(enc_out['lsp_base64'])
csv_loc_file.write(row + '\n')
else:
print('TEST FAILED:', idx+1)
return iok == len(enc_in_s)
# Parse command line arguments
parser = argparse.ArgumentParser()
parser.add_argument("--noencode",
help="test only the decoding part",
action="store_true")
parser.add_argument("--java",
help="encoding part with Java lib (C lib by default)",
action="store_true")
parser.add_argument("--csvtest",
help="saving file testDecoding.csv",
action="store_true")
args = parser.parse_args()
# clean output files
CSV_LSP_TST = 'testLSPDecoding.csv'
CSV_LOC_TST = 'testLocationDecoding.csv'
ENC_IN = 'encode_in.json'
ENC_OUT = 'encode_out.json'
DEC_OUT = 'decode_out.json'
if os.path.exists(ENC_OUT) and not args.noencode:
os.remove(ENC_OUT)
if os.path.exists(DEC_OUT):
os.remove(DEC_OUT)
if os.path.exists(DEC_OUT):
os.remove(DEC_OUT)
# testDecoding.csv, to be updated when necessary for junit5 test in ../java/src/test/resources
if args.csvtest:
CSV_LSP_FILE = open(CSV_LSP_TST, "w")
CSV_LOC_FILE = open(CSV_LOC_TST, "w")
HEADER = 'staff, countryCode, LTId, CRIexp, venueType, venueCat1, venueCat2, periodDuration, ct_periodStart, t_qrStart, SK_SA, PK_SA, lsp_base64\n'
CSV_LSP_FILE.write(HEADER)
HEADER = 'locationPhone, locationRegion, locationPin, t_periodStart, SK_SA, PK_SA, SK_MCTA, PK_MCTA, lsp_base64\n'
CSV_LOC_FILE.write(HEADER)
else:
CSV_LSP_FILE = None
CSV_LOC_FILE = None
# encode_in.json -> [lsps_encode] -> encode_out.json
if not args.noencode:
lsps_encode(ENC_IN, ENC_OUT, java=args.java)
# encode_out.json -> [lsps_decode] -> decode_out.json
lsps_decode(ENC_OUT, DEC_OUT)
# compare parameters input or generated (time, ltid) and output paramaters
if lsps_cmp(ENC_IN, ENC_OUT, DEC_OUT, CSV_LSP_FILE, CSV_LOC_FILE):
print('ALL TESTS PASS')
else:
print('TESTS FAILED')
if args.csvtest:
CSV_LSP_FILE.close()
CSV_LOC_FILE.close()
lsp_cmp(enc_in_s[idx], enc_out_s[idx], dec_out_s[idx])
if CSV_TEST_FILES_GENERATION:
save_lsp_encoding_decoding_results(enc_in_s[idx], enc_out_s[idx], csv_lsp_file, csv_loc_file)
def save_lsp_encoding_decoding_results(enc_in, enc_out, csv_lsp_file, csv_loc_file):
sep = ', '
if csv_lsp_file is not None:
row = str(enc_in['staff']) + sep + str(enc_in['countryCode']) + sep
row += str(enc_out['LTId']) + sep + str(enc_in['CRIexp']) + sep
row += str(enc_in['venueType']) + sep + str(enc_in['venueCategory1']) + sep
row += str(enc_in['venueCategory2']) + sep + str(enc_in['periodDuration']) + sep
row += str(enc_out['ct_periodStart']) + sep + str(enc_out['t_qrStart']) + sep
row += str(enc_in['SK_SA']) + sep + str(enc_in['PK_SA']) + sep
row += str(enc_out['lsp_base64'])
with open(csv_lsp_file, 'a') as outFile:
outFile.write(row + '\n')
if csv_loc_file is not None and enc_in.get('locationPhone') is not None:
row = str(enc_in['locationPhone']) + sep + str(enc_in['locationRegion']) + sep
row += str(enc_in['locationPIN']) + sep + str(enc_out['ct_periodStart']*3600)
row += sep + str(enc_in['SK_SA']) + sep + str(enc_in['PK_SA']) + sep
row += str(enc_in['SK_MCTA']) + sep + str(enc_in['PK_MCTA']) + sep
row += str(enc_out['lsp_base64'])
with open(csv_loc_file, 'a') as outFile:
outFile.write(row + '\n')
if __name__ == "__main__":
# Parse command line arguments
parser = argparse.ArgumentParser()
parser.add_argument("--csvtest",
help="saving file testDecoding.csv",
action="store_true")
args = parser.parse_args()
if args.csvtest:
CSV_TEST_FILES_GENERATION = True
with open(CSV_LSP_TST, "w") as outFile:
HEADER = 'staff, countryCode, LTId, CRIexp, venueType, venueCat1, venueCat2, periodDuration, ct_periodStart, t_qrStart, SK_SA, PK_SA, lsp_base64\n'
outFile.write(HEADER)
with open(CSV_LOC_TST, "w") as outFile:
HEADER = 'locationPhone, locationRegion, locationPin, t_periodStart, SK_SA, PK_SA, SK_MCTA, PK_MCTA, lsp_base64\n'
outFile.write(HEADER)
sys.argv = [ sys.argv[0] ]
unittest.main()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment