1
0
mirror of synced 2025-12-30 21:02:43 -05:00
Files
airbyte/tools/git_hooks/tests/test_spec_linter.py
Yaroslav Dudar 7ec756fe12 🎆 Spec.json linter (#6366)
added python script linter for spec.json validation
2021-09-30 13:01:20 +03:00

181 lines
6.9 KiB
Python

#
# MIT License
#
# Copyright (c) 2020 Airbyte
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#
import json
import unittest.mock as mock
import pytest
import spec_linter
def test_get_full_field_name():
assert spec_linter.get_full_field_name("field") == "field"
assert spec_linter.get_full_field_name("field", ["root"]) == "root.field"
assert spec_linter.get_full_field_name("field", ["root", "fake_field", "0"]) == "root.fake_field.0.field"
def test_fetch_oneof_schemas():
# case 1)
root_schema = {"oneOf": [{"properties": {1: 1}}, {"values": [1, 2, 3]}]}
schemas = spec_linter.fetch_oneof_schemas(root_schema)
assert len(schemas) == 1
assert schemas[0] == {"properties": {1: 1}}
# case 2)
root_schema = {"oneOf": [{"properties": {1: 1}}, {"properties": {2: 2}}]}
schemas = spec_linter.fetch_oneof_schemas(root_schema)
assert len(schemas) == 2
assert schemas[0] == {"properties": {1: 1}}
assert schemas[1] == {"properties": {2: 2}}
@pytest.mark.parametrize(
"schema,error_text",
[
({"type": "string", "title": "Field"}, "Check failed for field"),
({"type": "string", "description": "Format: YYYY-MM-DDTHH:mm:ss[Z]."}, "Check failed for field"),
(
{"type": "string", "title": "Field", "description": "Format: YYYY-MM-DDTHH:mm:ss[Z].", "oneOf": "invalid"},
"Incorrect oneOf schema in field",
),
(
{
"type": "string",
"title": "Field",
"description": "Format: YYYY-MM-DDTHH:mm:ss[Z].",
"examples": ["2020-01-01T00:00:00Z"],
"oneOf": [1, 2, 3],
},
"Incorrect oneOf schema in field",
),
],
)
def test_validate_field(schema, error_text):
errors = spec_linter.validate_field("field", schema, [])
assert len(errors) == 1
assert error_text in errors[0]
def test_validate_field_invalid_schema_and_oneof():
schema = {
"type": "string",
"description": "Format: YYYY-MM-DDTHH:mm:ss[Z].",
"examples": ["2020-01-01T00:00:00Z"],
"oneOf": [1, 2, 3],
}
errors = spec_linter.validate_field("field", schema, ["root"])
assert len(errors) == 2
assert "Check failed for field" in errors[0]
assert "Incorrect oneOf schema in field" in errors[1]
def test_read_spec_file():
# file is not json serializable
with mock.patch("builtins.open", mock.mock_open(read_data="test")):
assert not spec_linter.read_spec_file("path_1")
# property field is not exist
with mock.patch("builtins.open", mock.mock_open(read_data='{"connectionSpecification": "test"}')):
assert not spec_linter.read_spec_file("path_1")
# valid schema
valid_schema = {"connectionSpecification": {"properties": {}}}
with mock.patch("builtins.open", mock.mock_open(read_data=json.dumps(valid_schema))):
assert spec_linter.read_spec_file("path_1")
# schema with invalid field
invalid_schema = {"connectionSpecification": {"properties": {"field": {"title": "Field", "type": "string"}}}}
with mock.patch("builtins.open", mock.mock_open(read_data=json.dumps(invalid_schema))):
assert not spec_linter.read_spec_file("path_1")
def test_validate_schema_failed():
schema = {
"access_token": {"type": "string", "airbyte_secret": True, "description": "API Key."},
"store_name": {"type": "string", "title": "Store name."},
"start_date": {
"title": "Start Date",
"type": "string",
"description": "The date from which you'd like to replicate the data",
"examples": ["2021-01-01T00:00:00Z"],
},
}
errors = spec_linter.validate_schema("path", schema, ["root"])
assert len(errors) == 2
assert "Check failed for field" in errors[0] and "root.access_token" in errors[0]
assert "Check failed for field" in errors[1] and "root.store_name" in errors[1]
def test_validate_schema_success():
schema = {
"access_token": {"type": "string", "airbyte_secret": True, "description": "API Key.", "title": "Key"},
"store_name": {"type": "string", "description": "My description", "title": "My name"},
"limit": {
"title": "Records Limit",
"type": "integer",
"description": "Just a limit",
},
}
errors = spec_linter.validate_schema("path", schema, ["root"])
assert len(errors) == 0
def test_validate_schema_with_nested_oneof():
schema = {
"store_name": {"type": "string", "description": "Store name."},
"start_date": {
"title": "Start Date",
"type": "string",
"description": "The date from which you'd like to replicate the data",
},
"nested_field": {
"type": "object",
"title": "Nested field title",
"description": "Nested field description",
"oneOf": [
{
"type": "object",
"properties": {
"settings": {
"type": "object",
"title": "Settings",
"description": "blah-blah-blah",
"oneOf": [
{"type": "object", "properties": {"access_token": {"type": "object"}}},
{"type": "string", "multipleOf": 3},
],
}
},
},
{"type": "string", "title": "Start Date"},
],
},
}
errors = spec_linter.validate_schema("path", schema, [])
assert len(errors) == 2
# check error type
assert "Check failed for field" == errors[0][0]
assert "Check failed for field" == errors[1][0]
# check failed fields
assert "store_name" == errors[0][1]
assert "nested_field.0.settings.0.access_token" == errors[1][1]