def test_json_response_generation(xls_input, expected_response_file): """ tests if json response is correctly generated for all combinations of requests """ data = convert_service_sheet(xls_input, eqpt_filename) equipment = load_equipment(eqpt_filename) network = load_network(xls_input, equipment) p_db = equipment['SI']['default'].power_dbm p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min,\ equipment['SI']['default'].f_max, equipment['SI']['default'].spacing)) build_network(network, equipment, p_db, p_total_db) rqs = requests_from_json(data, equipment) rqs = correct_route_list(network, rqs) dsjn = disjunctions_from_json(data) dsjn = correct_disjn(dsjn) rqs, dsjn = requests_aggregation(rqs, dsjn) pths = compute_path_dsjctn(network, equipment, rqs, dsjn) propagatedpths = compute_path_with_disjunction(network, equipment, rqs, pths) result = [] for i, pth in enumerate(propagatedpths): result.append(Result_element(rqs[i], pth)) temp = { 'response': [n.json for n in result] } # load expected result and compare keys # (not values at this stage) with open(expected_response_file) as jsonfile: expected = load(jsonfile) for i, response in enumerate(temp['response']): assert compare_response(expected['response'][i], response)
def post(self): data = request.get_json() equipment = load_equipment('examples/2019-demo-equipment.json') topo_json = load_json('examples/2019-demo-topology.json') network = network_from_json(topo_json, equipment) try: propagatedpths, reversed_propagatedpths, rqs = compute_requests( network, data, equipment) # Generate the output result = [] #assumes that list of rqs and list of propgatedpths have same order for i, pth in enumerate(propagatedpths): result.append( Result_element(rqs[i], pth, reversed_propagatedpths[i])) return {"result": path_result_json(result)}, 201 except ServiceError as this_e: msg = f'Service error: {this_e}' return {"result": msg}, 400
def launch_cli(network, data, equipment): """ Compute requests using network, data and equipment with client line interface """ propagatedpths, reversed_propagatedpths, rqs = compute_requests( network, data, equipment) #Generate the output if ARGS.output: result = [] # assumes that list of rqs and list of propgatedpths have same order for i, pth in enumerate(propagatedpths): result.append( Result_element(rqs[i], pth, reversed_propagatedpths[i])) temp = path_result_json(result) fnamecsv = f'{str(ARGS.output)[0:len(str(ARGS.output))-len(str(ARGS.output.suffix))]}.csv' fnamejson = f'{str(ARGS.output)[0:len(str(ARGS.output))-len(str(ARGS.output.suffix))]}.json' with open(fnamejson, 'w', encoding='utf-8') as fjson: fjson.write( dumps(path_result_json(result), indent=2, ensure_ascii=False)) with open(fnamecsv, "w", encoding='utf-8') as fcsv: jsontocsv(temp, equipment, fcsv) print('\x1b[1;34;40m' + f'saving in {ARGS.output} and {fnamecsv}' + '\x1b[0m')
line = [f'{rqs[i].request_id}', f' {rqs[i].source} to {rqs[i].destination} : ', f'{round(mean(p[-1].snr),2)}',\ f'{round(mean(p[-1].snr+lin2db(rqs[i].baud_rate/(12.5e9))),2)}',\ f'{rqs[i].OSNR}', f'{rqs[i].tsp_mode}' , f'{round(rqs[i].path_bandwidth * 1e-9,2)}' , f'{ceil(rqs[i].path_bandwidth / rqs[i].bit_rate) }'] else: line = [f'{rqs[i].request_id}',f' {rqs[i].source} to {rqs[i].destination} : not feasible '] data.append(line) col_width = max(len(word) for row in data for word in row[2:]) # padding firstcol_width = max(len(row[0]) for row in data ) # padding secondcol_width = max(len(row[1]) for row in data ) # padding for row in data: firstcol = ''.join(row[0].ljust(firstcol_width)) secondcol = ''.join(row[1].ljust(secondcol_width)) remainingcols = ''.join(word.center(col_width,' ') for word in row[2:]) print(f'{firstcol} {secondcol} {remainingcols}') if args.output : result = [] # assumes that list of rqs and list of propgatedpths have same order for i,p in enumerate(propagatedpths): result.append(Result_element(rqs[i],p)) temp = path_result_json(result) fnamecsv = f'{str(args.output)[0:len(str(args.output))-len(str(args.output.suffix))]}.csv' fnamejson = f'{str(args.output)[0:len(str(args.output))-len(str(args.output.suffix))]}.json' with open(fnamejson, 'w', encoding='utf-8') as f: f.write(dumps(path_result_json(result), indent=2, ensure_ascii=False)) with open(fnamecsv,"w", encoding='utf-8') as fcsv : jsontocsv(temp,equipment,fcsv) print('\x1b[1;34;40m'+f'saving in {args.output} and {fnamecsv}'+ '\x1b[0m')
def main(args): """ main function that calls all functions """ LOGGER.info( f'Computing path requests {args.service_filename} into JSON format') print('\x1b[1;34;40m' +\ f'Computing path requests {args.service_filename} into JSON format'+ '\x1b[0m') # for debug # print( args.eqpt_filename) try: data = load_requests(args.service_filename, args.eqpt_filename, args.bidir) equipment = load_equipment(args.eqpt_filename) network = load_network(args.network_filename, equipment) except EquipmentConfigError as this_e: print( f'{ansi_escapes.red}Configuration error in the equipment library:{ansi_escapes.reset} {this_e}' ) exit(1) except NetworkTopologyError as this_e: print( f'{ansi_escapes.red}Invalid network definition:{ansi_escapes.reset} {this_e}' ) exit(1) except ConfigurationError as this_e: print( f'{ansi_escapes.red}Configuration error:{ansi_escapes.reset} {this_e}' ) exit(1) except ServiceError as this_e: print(f'{ansi_escapes.red}Service error:{ansi_escapes.reset} {this_e}') exit(1) # Build the network once using the default power defined in SI in eqpt config # TODO power density: db2linp(ower_dbm": 0)/power_dbm": 0 * nb channels as defined by # spacing, f_min and f_max p_db = equipment['SI']['default'].power_dbm p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min,\ equipment['SI']['default'].f_max, equipment['SI']['default'].spacing)) build_network(network, equipment, p_db, p_total_db) save_network(args.network_filename, network) oms_list = build_oms_list(network, equipment) try: rqs = requests_from_json(data, equipment) except ServiceError as this_e: print(f'{ansi_escapes.red}Service error:{ansi_escapes.reset} {this_e}') exit(1) # check that request ids are unique. Non unique ids, may # mess the computation: better to stop the computation all_ids = [r.request_id for r in rqs] if len(all_ids) != len(set(all_ids)): for item in list(set(all_ids)): all_ids.remove(item) msg = f'Requests id {all_ids} are not unique' LOGGER.critical(msg) exit() try: rqs = correct_route_list(network, rqs) except ServiceError as this_e: print(f'{ansi_escapes.red}Service error:{ansi_escapes.reset} {this_e}') exit(1) # pths = compute_path(network, equipment, rqs) dsjn = disjunctions_from_json(data) print('\x1b[1;34;40m' + f'List of disjunctions' + '\x1b[0m') print(dsjn) # need to warn or correct in case of wrong disjunction form # disjunction must not be repeated with same or different ids dsjn = correct_disjn(dsjn) # Aggregate demands with same exact constraints print('\x1b[1;34;40m' + f'Aggregating similar requests' + '\x1b[0m') rqs, dsjn = requests_aggregation(rqs, dsjn) # TODO export novel set of aggregated demands in a json file print('\x1b[1;34;40m' + 'The following services have been requested:' + '\x1b[0m') print(rqs) print('\x1b[1;34;40m' + f'Computing all paths with constraints' + '\x1b[0m') try: pths = compute_path_dsjctn(network, equipment, rqs, dsjn) except DisjunctionError as this_e: print( f'{ansi_escapes.red}Disjunction error:{ansi_escapes.reset} {this_e}' ) exit(1) print('\x1b[1;34;40m' + f'Propagating on selected path' + '\x1b[0m') propagatedpths, reversed_pths, reversed_propagatedpths = \ compute_path_with_disjunction(network, equipment, rqs, pths) # Note that deepcopy used in compute_path_with_disjunction returns # a list of nodes which are not belonging to network (they are copies of the node objects). # so there can not be propagation on these nodes. pth_assign_spectrum(pths, rqs, oms_list, reversed_pths) print('\x1b[1;34;40m' + f'Result summary' + '\x1b[0m') header = ['req id', ' demand', ' snr@bandwidth A-Z (Z-A)', ' [email protected] A-Z (Z-A)',\ ' Receiver minOSNR', ' mode', ' Gbit/s', ' nb of tsp pairs',\ 'N,M or blocking reason'] data = [] data.append(header) for i, this_p in enumerate(propagatedpths): rev_pth = reversed_propagatedpths[i] if rev_pth and this_p: psnrb = f'{round(mean(this_p[-1].snr),2)} ({round(mean(rev_pth[-1].snr),2)})' psnr = f'{round(mean(this_p[-1].snr_01nm), 2)}' +\ f' ({round(mean(rev_pth[-1].snr_01nm),2)})' elif this_p: psnrb = f'{round(mean(this_p[-1].snr),2)}' psnr = f'{round(mean(this_p[-1].snr_01nm),2)}' try: if rqs[i].blocking_reason in BLOCKING_NOPATH: line = [f'{rqs[i].request_id}', f' {rqs[i].source} to {rqs[i].destination} :',\ f'-', f'-', f'-', f'{rqs[i].tsp_mode}', f'{round(rqs[i].path_bandwidth * 1e-9,2)}',\ f'-', f'{rqs[i].blocking_reason}'] else: line = [f'{rqs[i].request_id}', f' {rqs[i].source} to {rqs[i].destination} : ', psnrb,\ psnr, f'-', f'{rqs[i].tsp_mode}', f'{round(rqs[i].path_bandwidth * 1e-9, 2)}',\ f'-', f'{rqs[i].blocking_reason}'] except AttributeError: line = [f'{rqs[i].request_id}', f' {rqs[i].source} to {rqs[i].destination} : ', psnrb,\ psnr, f'{rqs[i].OSNR}', f'{rqs[i].tsp_mode}', f'{round(rqs[i].path_bandwidth * 1e-9,2)}',\ f'{ceil(rqs[i].path_bandwidth / rqs[i].bit_rate) }', f'({rqs[i].N},{rqs[i].M})'] data.append(line) col_width = max(len(word) for row in data for word in row[2:]) # padding firstcol_width = max(len(row[0]) for row in data) # padding secondcol_width = max(len(row[1]) for row in data) # padding for row in data: firstcol = ''.join(row[0].ljust(firstcol_width)) secondcol = ''.join(row[1].ljust(secondcol_width)) remainingcols = ''.join( word.center(col_width, ' ') for word in row[2:]) print(f'{firstcol} {secondcol} {remainingcols}') print('\x1b[1;33;40m'+f'Result summary shows mean SNR and OSNR (average over all channels)' +\ '\x1b[0m') if args.output: result = [] # assumes that list of rqs and list of propgatedpths have same order for i, pth in enumerate(propagatedpths): result.append( Result_element(rqs[i], pth, reversed_propagatedpths[i])) temp = path_result_json(result) fnamecsv = f'{str(args.output)[0:len(str(args.output))-len(str(args.output.suffix))]}.csv' fnamejson = f'{str(args.output)[0:len(str(args.output))-len(str(args.output.suffix))]}.json' with open(fnamejson, 'w', encoding='utf-8') as fjson: fjson.write( dumps(path_result_json(result), indent=2, ensure_ascii=False)) with open(fnamecsv, "w", encoding='utf-8') as fcsv: jsontocsv(temp, equipment, fcsv) print('\x1b[1;34;40m' + f'saving in {args.output} and {fnamecsv}' + '\x1b[0m')
def test_json_response_generation(xls_input, expected_response_file): """ tests if json response is correctly generated for all combinations of requests """ data = convert_service_sheet(xls_input, eqpt_filename) # change one of the request with bidir option to cover bidir case as well data['path-request'][2]['bidirectional'] = True equipment = load_equipment(eqpt_filename) network = load_network(xls_input, equipment) p_db = equipment['SI']['default'].power_dbm p_total_db = p_db + lin2db(automatic_nch(equipment['SI']['default'].f_min,\ equipment['SI']['default'].f_max, equipment['SI']['default'].spacing)) build_network(network, equipment, p_db, p_total_db) oms_list = build_oms_list(network, equipment) rqs = requests_from_json(data, equipment) rqs = correct_route_list(network, rqs) dsjn = disjunctions_from_json(data) dsjn = correct_disjn(dsjn) rqs, dsjn = requests_aggregation(rqs, dsjn) pths = compute_path_dsjctn(network, equipment, rqs, dsjn) propagatedpths, reversed_pths, reversed_propagatedpths = \ compute_path_with_disjunction(network, equipment, rqs, pths) pth_assign_spectrum(pths, rqs, oms_list, reversed_pths) result = [] for i, pth in enumerate(propagatedpths): # test ServiceError handling : when M is zero at this point, the # json result should not be created if there is no blocking reason if i == 1: my_rq = deepcopy(rqs[i]) my_rq.M = 0 with pytest.raises(ServiceError): Result_element(my_rq, pth, reversed_propagatedpths[i]).json my_rq.blocking_reason = 'NO_SPECTRUM' Result_element(my_rq, pth, reversed_propagatedpths[i]).json result.append(Result_element(rqs[i], pth, reversed_propagatedpths[i])) temp = {'response': [n.json for n in result]} # load expected result and compare keys and values with open(expected_response_file) as jsonfile: expected = load(jsonfile) # since we changes bidir attribute of request#2, need to add the corresponding # metric in response for i, response in enumerate(temp['response']): if i == 2: # compare response must be False because z-a metric is missing # (request with bidir option to cover bidir case) assert not compare_response(expected['response'][i], response) print(f'response {response["response-id"]} should not match') expected['response'][2]['path-properties']['z-a-path-metric'] = [{ 'metric-type': 'SNR-bandwidth', 'accumulative-value': 22.809999999999999 }, { 'metric-type': 'SNR-0.1nm', 'accumulative-value': 26.890000000000001 }, { 'metric-type': 'OSNR-bandwidth', 'accumulative-value': 26.239999999999998 }, { 'metric-type': 'OSNR-0.1nm', 'accumulative-value': 30.32 }, { 'metric-type': 'reference_power', 'accumulative-value': 0.0012589254117941673 }, { 'metric-type': 'path_bandwidth', 'accumulative-value': 60000000000.0 }] # test should be OK now else: assert compare_response(expected['response'][i], response) print(f'response {response["response-id"]} is not correct')
print(pths) test = compute_path(network, equipment, pths) #TODO write results header = ['demand', 'snr@bandwidth', '[email protected]', 'Receiver minOSNR'] data = [] data.append(header) for i, p in enumerate(test): if p: line = [f'{pths[i].source} to {pths[i].destination} : ', f'{round(mean(p[-1].snr),2)}',\ f'{round(mean(p[-1].snr+lin2db(pths[i].baud_rate/(12.5e9))),2)}',\ f'{pths[i].OSNR}'] else: line = [f'no path from {pths[i].source} to {pths[i].destination} '] data.append(line) col_width = max(len(word) for row in data for word in row) # padding for row in data: print(''.join(word.ljust(col_width) for word in row)) if args.output: result = [] for p in test: result.append(Result_element(pths[test.index(p)], p)) with open(args.output, 'w') as f: f.write(dumps(path_result_json(result), indent=2)) fnamecsv = next(s for s in args.output.split('.')) + '.csv' with open(fnamecsv, "w") as fcsv: jsontocsv(path_result_json(result), equipment, fcsv)