11cb0ef41Sopenharmony_ci#!/usr/bin/env python 21cb0ef41Sopenharmony_ci# Copyright (c) 2011 Google Inc. All rights reserved. 31cb0ef41Sopenharmony_ci# 41cb0ef41Sopenharmony_ci# Redistribution and use in source and binary forms, with or without 51cb0ef41Sopenharmony_ci# modification, are permitted provided that the following conditions are 61cb0ef41Sopenharmony_ci# met: 71cb0ef41Sopenharmony_ci# 81cb0ef41Sopenharmony_ci# * Redistributions of source code must retain the above copyright 91cb0ef41Sopenharmony_ci# notice, this list of conditions and the following disclaimer. 101cb0ef41Sopenharmony_ci# * Redistributions in binary form must reproduce the above 111cb0ef41Sopenharmony_ci# copyright notice, this list of conditions and the following disclaimer 121cb0ef41Sopenharmony_ci# in the documentation and/or other materials provided with the 131cb0ef41Sopenharmony_ci# distribution. 141cb0ef41Sopenharmony_ci# * Neither the name of Google Inc. nor the names of its 151cb0ef41Sopenharmony_ci# contributors may be used to endorse or promote products derived from 161cb0ef41Sopenharmony_ci# this software without specific prior written permission. 171cb0ef41Sopenharmony_ci# 181cb0ef41Sopenharmony_ci# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 191cb0ef41Sopenharmony_ci# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 201cb0ef41Sopenharmony_ci# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 211cb0ef41Sopenharmony_ci# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 221cb0ef41Sopenharmony_ci# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 231cb0ef41Sopenharmony_ci# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 241cb0ef41Sopenharmony_ci# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 251cb0ef41Sopenharmony_ci# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 261cb0ef41Sopenharmony_ci# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 271cb0ef41Sopenharmony_ci# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 281cb0ef41Sopenharmony_ci# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 291cb0ef41Sopenharmony_ci# 301cb0ef41Sopenharmony_ci# Inspector protocol validator. 311cb0ef41Sopenharmony_ci# 321cb0ef41Sopenharmony_ci# Tests that subsequent protocol changes are not breaking backwards compatibility. 331cb0ef41Sopenharmony_ci# Following violations are reported: 341cb0ef41Sopenharmony_ci# 351cb0ef41Sopenharmony_ci# - Domain has been removed 361cb0ef41Sopenharmony_ci# - Command has been removed 371cb0ef41Sopenharmony_ci# - Required command parameter was added or changed from optional 381cb0ef41Sopenharmony_ci# - Required response parameter was removed or changed to optional 391cb0ef41Sopenharmony_ci# - Event has been removed 401cb0ef41Sopenharmony_ci# - Required event parameter was removed or changed to optional 411cb0ef41Sopenharmony_ci# - Parameter type has changed. 421cb0ef41Sopenharmony_ci# 431cb0ef41Sopenharmony_ci# For the parameters with composite types the above checks are also applied 441cb0ef41Sopenharmony_ci# recursively to every property of the type. 451cb0ef41Sopenharmony_ci# 461cb0ef41Sopenharmony_ci# Adding --show_changes to the command line prints out a list of valid public API changes. 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_cifrom __future__ import print_function 491cb0ef41Sopenharmony_ciimport copy 501cb0ef41Sopenharmony_ciimport os.path 511cb0ef41Sopenharmony_ciimport optparse 521cb0ef41Sopenharmony_ciimport sys 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ciimport pdl 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_citry: 571cb0ef41Sopenharmony_ci import json 581cb0ef41Sopenharmony_ciexcept ImportError: 591cb0ef41Sopenharmony_ci import simplejson as json 601cb0ef41Sopenharmony_ci 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_cidef list_to_map(items, key): 631cb0ef41Sopenharmony_ci result = {} 641cb0ef41Sopenharmony_ci for item in items: 651cb0ef41Sopenharmony_ci if "experimental" not in item and "hidden" not in item: 661cb0ef41Sopenharmony_ci result[item[key]] = item 671cb0ef41Sopenharmony_ci return result 681cb0ef41Sopenharmony_ci 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_cidef named_list_to_map(container, name, key): 711cb0ef41Sopenharmony_ci if name in container: 721cb0ef41Sopenharmony_ci return list_to_map(container[name], key) 731cb0ef41Sopenharmony_ci return {} 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_cidef removed(reverse): 771cb0ef41Sopenharmony_ci if reverse: 781cb0ef41Sopenharmony_ci return "added" 791cb0ef41Sopenharmony_ci return "removed" 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_cidef required(reverse): 831cb0ef41Sopenharmony_ci if reverse: 841cb0ef41Sopenharmony_ci return "optional" 851cb0ef41Sopenharmony_ci return "required" 861cb0ef41Sopenharmony_ci 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_cidef compare_schemas(d_1, d_2, reverse): 891cb0ef41Sopenharmony_ci errors = [] 901cb0ef41Sopenharmony_ci domains_1 = copy.deepcopy(d_1) 911cb0ef41Sopenharmony_ci domains_2 = copy.deepcopy(d_2) 921cb0ef41Sopenharmony_ci types_1 = normalize_types_in_schema(domains_1) 931cb0ef41Sopenharmony_ci types_2 = normalize_types_in_schema(domains_2) 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci domains_by_name_1 = list_to_map(domains_1, "domain") 961cb0ef41Sopenharmony_ci domains_by_name_2 = list_to_map(domains_2, "domain") 971cb0ef41Sopenharmony_ci 981cb0ef41Sopenharmony_ci for name in domains_by_name_1: 991cb0ef41Sopenharmony_ci domain_1 = domains_by_name_1[name] 1001cb0ef41Sopenharmony_ci if name not in domains_by_name_2: 1011cb0ef41Sopenharmony_ci errors.append("%s: domain has been %s" % (name, removed(reverse))) 1021cb0ef41Sopenharmony_ci continue 1031cb0ef41Sopenharmony_ci compare_domains(domain_1, domains_by_name_2[name], types_1, types_2, errors, reverse) 1041cb0ef41Sopenharmony_ci return errors 1051cb0ef41Sopenharmony_ci 1061cb0ef41Sopenharmony_ci 1071cb0ef41Sopenharmony_cidef compare_domains(domain_1, domain_2, types_map_1, types_map_2, errors, reverse): 1081cb0ef41Sopenharmony_ci domain_name = domain_1["domain"] 1091cb0ef41Sopenharmony_ci commands_1 = named_list_to_map(domain_1, "commands", "name") 1101cb0ef41Sopenharmony_ci commands_2 = named_list_to_map(domain_2, "commands", "name") 1111cb0ef41Sopenharmony_ci for name in commands_1: 1121cb0ef41Sopenharmony_ci command_1 = commands_1[name] 1131cb0ef41Sopenharmony_ci if name not in commands_2: 1141cb0ef41Sopenharmony_ci errors.append("%s.%s: command has been %s" % (domain_1["domain"], name, removed(reverse))) 1151cb0ef41Sopenharmony_ci continue 1161cb0ef41Sopenharmony_ci compare_commands(domain_name, command_1, commands_2[name], types_map_1, types_map_2, errors, reverse) 1171cb0ef41Sopenharmony_ci 1181cb0ef41Sopenharmony_ci events_1 = named_list_to_map(domain_1, "events", "name") 1191cb0ef41Sopenharmony_ci events_2 = named_list_to_map(domain_2, "events", "name") 1201cb0ef41Sopenharmony_ci for name in events_1: 1211cb0ef41Sopenharmony_ci event_1 = events_1[name] 1221cb0ef41Sopenharmony_ci if name not in events_2: 1231cb0ef41Sopenharmony_ci errors.append("%s.%s: event has been %s" % (domain_1["domain"], name, removed(reverse))) 1241cb0ef41Sopenharmony_ci continue 1251cb0ef41Sopenharmony_ci compare_events(domain_name, event_1, events_2[name], types_map_1, types_map_2, errors, reverse) 1261cb0ef41Sopenharmony_ci 1271cb0ef41Sopenharmony_ci 1281cb0ef41Sopenharmony_cidef compare_commands(domain_name, command_1, command_2, types_map_1, types_map_2, errors, reverse): 1291cb0ef41Sopenharmony_ci context = domain_name + "." + command_1["name"] 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_ci params_1 = named_list_to_map(command_1, "parameters", "name") 1321cb0ef41Sopenharmony_ci params_2 = named_list_to_map(command_2, "parameters", "name") 1331cb0ef41Sopenharmony_ci # Note the reversed order: we allow removing but forbid adding parameters. 1341cb0ef41Sopenharmony_ci compare_params_list(context, "parameter", params_2, params_1, types_map_2, types_map_1, 0, errors, not reverse) 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_ci returns_1 = named_list_to_map(command_1, "returns", "name") 1371cb0ef41Sopenharmony_ci returns_2 = named_list_to_map(command_2, "returns", "name") 1381cb0ef41Sopenharmony_ci compare_params_list(context, "response parameter", returns_1, returns_2, types_map_1, types_map_2, 0, errors, reverse) 1391cb0ef41Sopenharmony_ci 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_cidef compare_events(domain_name, event_1, event_2, types_map_1, types_map_2, errors, reverse): 1421cb0ef41Sopenharmony_ci context = domain_name + "." + event_1["name"] 1431cb0ef41Sopenharmony_ci params_1 = named_list_to_map(event_1, "parameters", "name") 1441cb0ef41Sopenharmony_ci params_2 = named_list_to_map(event_2, "parameters", "name") 1451cb0ef41Sopenharmony_ci compare_params_list(context, "parameter", params_1, params_2, types_map_1, types_map_2, 0, errors, reverse) 1461cb0ef41Sopenharmony_ci 1471cb0ef41Sopenharmony_ci 1481cb0ef41Sopenharmony_cidef compare_params_list(context, kind, params_1, params_2, types_map_1, types_map_2, depth, errors, reverse): 1491cb0ef41Sopenharmony_ci for name in params_1: 1501cb0ef41Sopenharmony_ci param_1 = params_1[name] 1511cb0ef41Sopenharmony_ci if name not in params_2: 1521cb0ef41Sopenharmony_ci if "optional" not in param_1: 1531cb0ef41Sopenharmony_ci errors.append("%s.%s: required %s has been %s" % (context, name, kind, removed(reverse))) 1541cb0ef41Sopenharmony_ci continue 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_ci param_2 = params_2[name] 1571cb0ef41Sopenharmony_ci if param_2 and "optional" in param_2 and "optional" not in param_1: 1581cb0ef41Sopenharmony_ci errors.append("%s.%s: %s %s is now %s" % (context, name, required(reverse), kind, required(not reverse))) 1591cb0ef41Sopenharmony_ci continue 1601cb0ef41Sopenharmony_ci type_1 = extract_type(param_1, types_map_1, errors) 1611cb0ef41Sopenharmony_ci type_2 = extract_type(param_2, types_map_2, errors) 1621cb0ef41Sopenharmony_ci compare_types(context + "." + name, kind, type_1, type_2, types_map_1, types_map_2, depth, errors, reverse) 1631cb0ef41Sopenharmony_ci 1641cb0ef41Sopenharmony_ci 1651cb0ef41Sopenharmony_cidef compare_types(context, kind, type_1, type_2, types_map_1, types_map_2, depth, errors, reverse): 1661cb0ef41Sopenharmony_ci if depth > 5: 1671cb0ef41Sopenharmony_ci return 1681cb0ef41Sopenharmony_ci 1691cb0ef41Sopenharmony_ci base_type_1 = type_1["type"] 1701cb0ef41Sopenharmony_ci base_type_2 = type_2["type"] 1711cb0ef41Sopenharmony_ci 1721cb0ef41Sopenharmony_ci # Binary and string have the same wire representation in JSON. 1731cb0ef41Sopenharmony_ci if ((base_type_1 == "string" and base_type_2 == "binary") or 1741cb0ef41Sopenharmony_ci (base_type_2 == "string" and base_type_1 == "binary")): 1751cb0ef41Sopenharmony_ci return 1761cb0ef41Sopenharmony_ci 1771cb0ef41Sopenharmony_ci if base_type_1 != base_type_2: 1781cb0ef41Sopenharmony_ci errors.append("%s: %s base type mismatch, '%s' vs '%s'" % (context, kind, base_type_1, base_type_2)) 1791cb0ef41Sopenharmony_ci elif base_type_1 == "object": 1801cb0ef41Sopenharmony_ci params_1 = named_list_to_map(type_1, "properties", "name") 1811cb0ef41Sopenharmony_ci params_2 = named_list_to_map(type_2, "properties", "name") 1821cb0ef41Sopenharmony_ci # If both parameters have the same named type use it in the context. 1831cb0ef41Sopenharmony_ci if "id" in type_1 and "id" in type_2 and type_1["id"] == type_2["id"]: 1841cb0ef41Sopenharmony_ci type_name = type_1["id"] 1851cb0ef41Sopenharmony_ci else: 1861cb0ef41Sopenharmony_ci type_name = "<object>" 1871cb0ef41Sopenharmony_ci context += " %s->%s" % (kind, type_name) 1881cb0ef41Sopenharmony_ci compare_params_list(context, "property", params_1, params_2, types_map_1, types_map_2, depth + 1, errors, reverse) 1891cb0ef41Sopenharmony_ci elif base_type_1 == "array": 1901cb0ef41Sopenharmony_ci item_type_1 = extract_type(type_1["items"], types_map_1, errors) 1911cb0ef41Sopenharmony_ci item_type_2 = extract_type(type_2["items"], types_map_2, errors) 1921cb0ef41Sopenharmony_ci compare_types(context, kind, item_type_1, item_type_2, types_map_1, types_map_2, depth + 1, errors, reverse) 1931cb0ef41Sopenharmony_ci 1941cb0ef41Sopenharmony_ci 1951cb0ef41Sopenharmony_cidef extract_type(typed_object, types_map, errors): 1961cb0ef41Sopenharmony_ci if "type" in typed_object: 1971cb0ef41Sopenharmony_ci result = {"id": "<transient>", "type": typed_object["type"]} 1981cb0ef41Sopenharmony_ci if typed_object["type"] == "object": 1991cb0ef41Sopenharmony_ci result["properties"] = [] 2001cb0ef41Sopenharmony_ci elif typed_object["type"] == "array": 2011cb0ef41Sopenharmony_ci result["items"] = typed_object["items"] 2021cb0ef41Sopenharmony_ci return result 2031cb0ef41Sopenharmony_ci elif "$ref" in typed_object: 2041cb0ef41Sopenharmony_ci ref = typed_object["$ref"] 2051cb0ef41Sopenharmony_ci if ref not in types_map: 2061cb0ef41Sopenharmony_ci errors.append("Can not resolve type: %s" % ref) 2071cb0ef41Sopenharmony_ci types_map[ref] = {"id": "<transient>", "type": "object"} 2081cb0ef41Sopenharmony_ci return types_map[ref] 2091cb0ef41Sopenharmony_ci 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_cidef normalize_types_in_schema(domains): 2121cb0ef41Sopenharmony_ci types = {} 2131cb0ef41Sopenharmony_ci for domain in domains: 2141cb0ef41Sopenharmony_ci domain_name = domain["domain"] 2151cb0ef41Sopenharmony_ci normalize_types(domain, domain_name, types) 2161cb0ef41Sopenharmony_ci return types 2171cb0ef41Sopenharmony_ci 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_cidef normalize_types(obj, domain_name, types): 2201cb0ef41Sopenharmony_ci if isinstance(obj, list): 2211cb0ef41Sopenharmony_ci for item in obj: 2221cb0ef41Sopenharmony_ci normalize_types(item, domain_name, types) 2231cb0ef41Sopenharmony_ci elif isinstance(obj, dict): 2241cb0ef41Sopenharmony_ci for key, value in obj.items(): 2251cb0ef41Sopenharmony_ci if key == "$ref" and value.find(".") == -1: 2261cb0ef41Sopenharmony_ci obj[key] = "%s.%s" % (domain_name, value) 2271cb0ef41Sopenharmony_ci elif key == "id": 2281cb0ef41Sopenharmony_ci obj[key] = "%s.%s" % (domain_name, value) 2291cb0ef41Sopenharmony_ci types[obj[key]] = obj 2301cb0ef41Sopenharmony_ci else: 2311cb0ef41Sopenharmony_ci normalize_types(value, domain_name, types) 2321cb0ef41Sopenharmony_ci 2331cb0ef41Sopenharmony_ci 2341cb0ef41Sopenharmony_cidef load_schema(file_name, domains): 2351cb0ef41Sopenharmony_ci # pylint: disable=W0613 2361cb0ef41Sopenharmony_ci if not os.path.isfile(file_name): 2371cb0ef41Sopenharmony_ci return 2381cb0ef41Sopenharmony_ci input_file = open(file_name, "r") 2391cb0ef41Sopenharmony_ci parsed_json = pdl.loads(input_file.read(), file_name) 2401cb0ef41Sopenharmony_ci input_file.close() 2411cb0ef41Sopenharmony_ci domains += parsed_json["domains"] 2421cb0ef41Sopenharmony_ci return parsed_json["version"] 2431cb0ef41Sopenharmony_ci 2441cb0ef41Sopenharmony_ci 2451cb0ef41Sopenharmony_cidef self_test(): 2461cb0ef41Sopenharmony_ci def create_test_schema_1(): 2471cb0ef41Sopenharmony_ci return [ 2481cb0ef41Sopenharmony_ci { 2491cb0ef41Sopenharmony_ci "domain": "Network", 2501cb0ef41Sopenharmony_ci "types": [ 2511cb0ef41Sopenharmony_ci { 2521cb0ef41Sopenharmony_ci "id": "LoaderId", 2531cb0ef41Sopenharmony_ci "type": "string" 2541cb0ef41Sopenharmony_ci }, 2551cb0ef41Sopenharmony_ci { 2561cb0ef41Sopenharmony_ci "id": "Headers", 2571cb0ef41Sopenharmony_ci "type": "object" 2581cb0ef41Sopenharmony_ci }, 2591cb0ef41Sopenharmony_ci { 2601cb0ef41Sopenharmony_ci "id": "Request", 2611cb0ef41Sopenharmony_ci "type": "object", 2621cb0ef41Sopenharmony_ci "properties": [ 2631cb0ef41Sopenharmony_ci {"name": "url", "type": "string"}, 2641cb0ef41Sopenharmony_ci {"name": "method", "type": "string"}, 2651cb0ef41Sopenharmony_ci {"name": "headers", "$ref": "Headers"}, 2661cb0ef41Sopenharmony_ci {"name": "becameOptionalField", "type": "string"}, 2671cb0ef41Sopenharmony_ci {"name": "removedField", "type": "string"}, 2681cb0ef41Sopenharmony_ci ] 2691cb0ef41Sopenharmony_ci } 2701cb0ef41Sopenharmony_ci ], 2711cb0ef41Sopenharmony_ci "commands": [ 2721cb0ef41Sopenharmony_ci { 2731cb0ef41Sopenharmony_ci "name": "removedCommand", 2741cb0ef41Sopenharmony_ci }, 2751cb0ef41Sopenharmony_ci { 2761cb0ef41Sopenharmony_ci "name": "setExtraHTTPHeaders", 2771cb0ef41Sopenharmony_ci "parameters": [ 2781cb0ef41Sopenharmony_ci {"name": "headers", "$ref": "Headers"}, 2791cb0ef41Sopenharmony_ci {"name": "mismatched", "type": "string"}, 2801cb0ef41Sopenharmony_ci {"name": "becameOptional", "$ref": "Headers"}, 2811cb0ef41Sopenharmony_ci {"name": "removedRequired", "$ref": "Headers"}, 2821cb0ef41Sopenharmony_ci {"name": "becameRequired", "$ref": "Headers", "optional": True}, 2831cb0ef41Sopenharmony_ci {"name": "removedOptional", "$ref": "Headers", "optional": True}, 2841cb0ef41Sopenharmony_ci ], 2851cb0ef41Sopenharmony_ci "returns": [ 2861cb0ef41Sopenharmony_ci {"name": "mimeType", "type": "string"}, 2871cb0ef41Sopenharmony_ci {"name": "becameOptional", "type": "string"}, 2881cb0ef41Sopenharmony_ci {"name": "removedRequired", "type": "string"}, 2891cb0ef41Sopenharmony_ci {"name": "becameRequired", "type": "string", "optional": True}, 2901cb0ef41Sopenharmony_ci {"name": "removedOptional", "type": "string", "optional": True}, 2911cb0ef41Sopenharmony_ci ] 2921cb0ef41Sopenharmony_ci } 2931cb0ef41Sopenharmony_ci ], 2941cb0ef41Sopenharmony_ci "events": [ 2951cb0ef41Sopenharmony_ci { 2961cb0ef41Sopenharmony_ci "name": "requestWillBeSent", 2971cb0ef41Sopenharmony_ci "parameters": [ 2981cb0ef41Sopenharmony_ci {"name": "frameId", "type": "string", "experimental": True}, 2991cb0ef41Sopenharmony_ci {"name": "request", "$ref": "Request"}, 3001cb0ef41Sopenharmony_ci {"name": "becameOptional", "type": "string"}, 3011cb0ef41Sopenharmony_ci {"name": "removedRequired", "type": "string"}, 3021cb0ef41Sopenharmony_ci {"name": "becameRequired", "type": "string", "optional": True}, 3031cb0ef41Sopenharmony_ci {"name": "removedOptional", "type": "string", "optional": True}, 3041cb0ef41Sopenharmony_ci ] 3051cb0ef41Sopenharmony_ci }, 3061cb0ef41Sopenharmony_ci { 3071cb0ef41Sopenharmony_ci "name": "removedEvent", 3081cb0ef41Sopenharmony_ci "parameters": [ 3091cb0ef41Sopenharmony_ci {"name": "errorText", "type": "string"}, 3101cb0ef41Sopenharmony_ci {"name": "canceled", "type": "boolean", "optional": True} 3111cb0ef41Sopenharmony_ci ] 3121cb0ef41Sopenharmony_ci } 3131cb0ef41Sopenharmony_ci ] 3141cb0ef41Sopenharmony_ci }, 3151cb0ef41Sopenharmony_ci { 3161cb0ef41Sopenharmony_ci "domain": "removedDomain" 3171cb0ef41Sopenharmony_ci } 3181cb0ef41Sopenharmony_ci ] 3191cb0ef41Sopenharmony_ci 3201cb0ef41Sopenharmony_ci def create_test_schema_2(): 3211cb0ef41Sopenharmony_ci return [ 3221cb0ef41Sopenharmony_ci { 3231cb0ef41Sopenharmony_ci "domain": "Network", 3241cb0ef41Sopenharmony_ci "types": [ 3251cb0ef41Sopenharmony_ci { 3261cb0ef41Sopenharmony_ci "id": "LoaderId", 3271cb0ef41Sopenharmony_ci "type": "string" 3281cb0ef41Sopenharmony_ci }, 3291cb0ef41Sopenharmony_ci { 3301cb0ef41Sopenharmony_ci "id": "Request", 3311cb0ef41Sopenharmony_ci "type": "object", 3321cb0ef41Sopenharmony_ci "properties": [ 3331cb0ef41Sopenharmony_ci {"name": "url", "type": "string"}, 3341cb0ef41Sopenharmony_ci {"name": "method", "type": "string"}, 3351cb0ef41Sopenharmony_ci {"name": "headers", "type": "object"}, 3361cb0ef41Sopenharmony_ci {"name": "becameOptionalField", "type": "string", "optional": True}, 3371cb0ef41Sopenharmony_ci ] 3381cb0ef41Sopenharmony_ci } 3391cb0ef41Sopenharmony_ci ], 3401cb0ef41Sopenharmony_ci "commands": [ 3411cb0ef41Sopenharmony_ci { 3421cb0ef41Sopenharmony_ci "name": "addedCommand", 3431cb0ef41Sopenharmony_ci }, 3441cb0ef41Sopenharmony_ci { 3451cb0ef41Sopenharmony_ci "name": "setExtraHTTPHeaders", 3461cb0ef41Sopenharmony_ci "parameters": [ 3471cb0ef41Sopenharmony_ci {"name": "headers", "type": "object"}, 3481cb0ef41Sopenharmony_ci {"name": "mismatched", "type": "object"}, 3491cb0ef41Sopenharmony_ci {"name": "becameOptional", "type": "object", "optional": True}, 3501cb0ef41Sopenharmony_ci {"name": "addedRequired", "type": "object"}, 3511cb0ef41Sopenharmony_ci {"name": "becameRequired", "type": "object"}, 3521cb0ef41Sopenharmony_ci {"name": "addedOptional", "type": "object", "optional": True}, 3531cb0ef41Sopenharmony_ci ], 3541cb0ef41Sopenharmony_ci "returns": [ 3551cb0ef41Sopenharmony_ci {"name": "mimeType", "type": "string"}, 3561cb0ef41Sopenharmony_ci {"name": "becameOptional", "type": "string", "optional": True}, 3571cb0ef41Sopenharmony_ci {"name": "addedRequired", "type": "string"}, 3581cb0ef41Sopenharmony_ci {"name": "becameRequired", "type": "string"}, 3591cb0ef41Sopenharmony_ci {"name": "addedOptional", "type": "string", "optional": True}, 3601cb0ef41Sopenharmony_ci ] 3611cb0ef41Sopenharmony_ci } 3621cb0ef41Sopenharmony_ci ], 3631cb0ef41Sopenharmony_ci "events": [ 3641cb0ef41Sopenharmony_ci { 3651cb0ef41Sopenharmony_ci "name": "requestWillBeSent", 3661cb0ef41Sopenharmony_ci "parameters": [ 3671cb0ef41Sopenharmony_ci {"name": "request", "$ref": "Request"}, 3681cb0ef41Sopenharmony_ci {"name": "becameOptional", "type": "string", "optional": True}, 3691cb0ef41Sopenharmony_ci {"name": "addedRequired", "type": "string"}, 3701cb0ef41Sopenharmony_ci {"name": "becameRequired", "type": "string"}, 3711cb0ef41Sopenharmony_ci {"name": "addedOptional", "type": "string", "optional": True}, 3721cb0ef41Sopenharmony_ci ] 3731cb0ef41Sopenharmony_ci }, 3741cb0ef41Sopenharmony_ci { 3751cb0ef41Sopenharmony_ci "name": "addedEvent" 3761cb0ef41Sopenharmony_ci } 3771cb0ef41Sopenharmony_ci ] 3781cb0ef41Sopenharmony_ci }, 3791cb0ef41Sopenharmony_ci { 3801cb0ef41Sopenharmony_ci "domain": "addedDomain" 3811cb0ef41Sopenharmony_ci } 3821cb0ef41Sopenharmony_ci ] 3831cb0ef41Sopenharmony_ci 3841cb0ef41Sopenharmony_ci expected_errors = [ 3851cb0ef41Sopenharmony_ci "removedDomain: domain has been removed", 3861cb0ef41Sopenharmony_ci "Network.removedCommand: command has been removed", 3871cb0ef41Sopenharmony_ci "Network.removedEvent: event has been removed", 3881cb0ef41Sopenharmony_ci "Network.setExtraHTTPHeaders.mismatched: parameter base type mismatch, 'object' vs 'string'", 3891cb0ef41Sopenharmony_ci "Network.setExtraHTTPHeaders.addedRequired: required parameter has been added", 3901cb0ef41Sopenharmony_ci "Network.setExtraHTTPHeaders.becameRequired: optional parameter is now required", 3911cb0ef41Sopenharmony_ci "Network.setExtraHTTPHeaders.removedRequired: required response parameter has been removed", 3921cb0ef41Sopenharmony_ci "Network.setExtraHTTPHeaders.becameOptional: required response parameter is now optional", 3931cb0ef41Sopenharmony_ci "Network.requestWillBeSent.removedRequired: required parameter has been removed", 3941cb0ef41Sopenharmony_ci "Network.requestWillBeSent.becameOptional: required parameter is now optional", 3951cb0ef41Sopenharmony_ci "Network.requestWillBeSent.request parameter->Network.Request.removedField: required property has been removed", 3961cb0ef41Sopenharmony_ci "Network.requestWillBeSent.request parameter->Network.Request.becameOptionalField: required property is now optional", 3971cb0ef41Sopenharmony_ci ] 3981cb0ef41Sopenharmony_ci 3991cb0ef41Sopenharmony_ci expected_errors_reverse = [ 4001cb0ef41Sopenharmony_ci "addedDomain: domain has been added", 4011cb0ef41Sopenharmony_ci "Network.addedEvent: event has been added", 4021cb0ef41Sopenharmony_ci "Network.addedCommand: command has been added", 4031cb0ef41Sopenharmony_ci "Network.setExtraHTTPHeaders.mismatched: parameter base type mismatch, 'string' vs 'object'", 4041cb0ef41Sopenharmony_ci "Network.setExtraHTTPHeaders.removedRequired: required parameter has been removed", 4051cb0ef41Sopenharmony_ci "Network.setExtraHTTPHeaders.becameOptional: required parameter is now optional", 4061cb0ef41Sopenharmony_ci "Network.setExtraHTTPHeaders.addedRequired: required response parameter has been added", 4071cb0ef41Sopenharmony_ci "Network.setExtraHTTPHeaders.becameRequired: optional response parameter is now required", 4081cb0ef41Sopenharmony_ci "Network.requestWillBeSent.becameRequired: optional parameter is now required", 4091cb0ef41Sopenharmony_ci "Network.requestWillBeSent.addedRequired: required parameter has been added", 4101cb0ef41Sopenharmony_ci ] 4111cb0ef41Sopenharmony_ci 4121cb0ef41Sopenharmony_ci def is_subset(subset, superset, message): 4131cb0ef41Sopenharmony_ci for i in range(len(subset)): 4141cb0ef41Sopenharmony_ci if subset[i] not in superset: 4151cb0ef41Sopenharmony_ci sys.stderr.write("%s error: %s\n" % (message, subset[i])) 4161cb0ef41Sopenharmony_ci return False 4171cb0ef41Sopenharmony_ci return True 4181cb0ef41Sopenharmony_ci 4191cb0ef41Sopenharmony_ci def errors_match(expected, actual): 4201cb0ef41Sopenharmony_ci return (is_subset(actual, expected, "Unexpected") and 4211cb0ef41Sopenharmony_ci is_subset(expected, actual, "Missing")) 4221cb0ef41Sopenharmony_ci 4231cb0ef41Sopenharmony_ci return (errors_match(expected_errors, 4241cb0ef41Sopenharmony_ci compare_schemas(create_test_schema_1(), create_test_schema_2(), False)) and 4251cb0ef41Sopenharmony_ci errors_match(expected_errors_reverse, 4261cb0ef41Sopenharmony_ci compare_schemas(create_test_schema_2(), create_test_schema_1(), True))) 4271cb0ef41Sopenharmony_ci 4281cb0ef41Sopenharmony_ci 4291cb0ef41Sopenharmony_cidef load_domains_and_baselines(file_name, domains, baseline_domains): 4301cb0ef41Sopenharmony_ci version = load_schema(os.path.normpath(file_name), domains) 4311cb0ef41Sopenharmony_ci suffix = "-%s.%s.json" % (version["major"], version["minor"]) 4321cb0ef41Sopenharmony_ci baseline_file = file_name.replace(".json", suffix) 4331cb0ef41Sopenharmony_ci baseline_file = file_name.replace(".pdl", suffix) 4341cb0ef41Sopenharmony_ci load_schema(os.path.normpath(baseline_file), baseline_domains) 4351cb0ef41Sopenharmony_ci return version 4361cb0ef41Sopenharmony_ci 4371cb0ef41Sopenharmony_ci 4381cb0ef41Sopenharmony_cidef main(): 4391cb0ef41Sopenharmony_ci if not self_test(): 4401cb0ef41Sopenharmony_ci sys.stderr.write("Self-test failed") 4411cb0ef41Sopenharmony_ci return 1 4421cb0ef41Sopenharmony_ci 4431cb0ef41Sopenharmony_ci cmdline_parser = optparse.OptionParser() 4441cb0ef41Sopenharmony_ci cmdline_parser.add_option("--show_changes") 4451cb0ef41Sopenharmony_ci cmdline_parser.add_option("--expected_errors") 4461cb0ef41Sopenharmony_ci cmdline_parser.add_option("--stamp") 4471cb0ef41Sopenharmony_ci arg_options, arg_values = cmdline_parser.parse_args() 4481cb0ef41Sopenharmony_ci 4491cb0ef41Sopenharmony_ci if len(arg_values) < 1: 4501cb0ef41Sopenharmony_ci sys.stderr.write("Usage: %s [--show_changes] <protocol-1> [, <protocol-2>...]\n" % sys.argv[0]) 4511cb0ef41Sopenharmony_ci return 1 4521cb0ef41Sopenharmony_ci 4531cb0ef41Sopenharmony_ci domains = [] 4541cb0ef41Sopenharmony_ci baseline_domains = [] 4551cb0ef41Sopenharmony_ci version = load_domains_and_baselines(arg_values[0], domains, baseline_domains) 4561cb0ef41Sopenharmony_ci for dependency in arg_values[1:]: 4571cb0ef41Sopenharmony_ci load_domains_and_baselines(dependency, domains, baseline_domains) 4581cb0ef41Sopenharmony_ci 4591cb0ef41Sopenharmony_ci expected_errors = [] 4601cb0ef41Sopenharmony_ci if arg_options.expected_errors: 4611cb0ef41Sopenharmony_ci expected_errors_file = open(arg_options.expected_errors, "r") 4621cb0ef41Sopenharmony_ci expected_errors = json.loads(expected_errors_file.read())["errors"] 4631cb0ef41Sopenharmony_ci expected_errors_file.close() 4641cb0ef41Sopenharmony_ci 4651cb0ef41Sopenharmony_ci errors = compare_schemas(baseline_domains, domains, False) 4661cb0ef41Sopenharmony_ci unexpected_errors = [] 4671cb0ef41Sopenharmony_ci for i in range(len(errors)): 4681cb0ef41Sopenharmony_ci if errors[i] not in expected_errors: 4691cb0ef41Sopenharmony_ci unexpected_errors.append(errors[i]) 4701cb0ef41Sopenharmony_ci if len(unexpected_errors) > 0: 4711cb0ef41Sopenharmony_ci sys.stderr.write(" Compatibility checks FAILED\n") 4721cb0ef41Sopenharmony_ci for error in unexpected_errors: 4731cb0ef41Sopenharmony_ci sys.stderr.write(" %s\n" % error) 4741cb0ef41Sopenharmony_ci return 1 4751cb0ef41Sopenharmony_ci 4761cb0ef41Sopenharmony_ci if arg_options.show_changes: 4771cb0ef41Sopenharmony_ci changes = compare_schemas(domains, baseline_domains, True) 4781cb0ef41Sopenharmony_ci if len(changes) > 0: 4791cb0ef41Sopenharmony_ci print(" Public changes since %s:" % version) 4801cb0ef41Sopenharmony_ci for change in changes: 4811cb0ef41Sopenharmony_ci print(" %s" % change) 4821cb0ef41Sopenharmony_ci 4831cb0ef41Sopenharmony_ci if arg_options.stamp: 4841cb0ef41Sopenharmony_ci with open(arg_options.stamp, 'a') as _: 4851cb0ef41Sopenharmony_ci pass 4861cb0ef41Sopenharmony_ci 4871cb0ef41Sopenharmony_ciif __name__ == '__main__': 4881cb0ef41Sopenharmony_ci sys.exit(main()) 489