181 lines
6.9 KiB
Python
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]
|