KiCad PCB EDA Suite
Loading...
Searching...
No Matches
test_remote_provider_metadata.cpp
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 3 of the License, or (at your
9 * option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <boost/test/unit_test.hpp>
21
23
24
25namespace
26{
27wxFileName schemaPath()
28{
29 wxFileName schemaFile( wxString::FromUTF8( __FILE__ ) );
30 schemaFile.Normalize( wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | wxPATH_NORM_ABSOLUTE );
31 schemaFile.RemoveLastDir();
32 schemaFile.RemoveLastDir();
33 schemaFile.RemoveLastDir();
34 schemaFile.AppendDir( wxS( "resources" ) );
35 schemaFile.AppendDir( wxS( "schemas" ) );
36 schemaFile.SetFullName( wxS( "kicad-remote-provider-metadata-v1.schema.json" ) );
37 return schemaFile;
38}
39
40
41nlohmann::json validMetadata()
42{
43 return nlohmann::json{
44 { "provider_name", "Acme Parts" },
45 { "provider_version", "1.0.0" },
46 { "api_base_url", "https://provider.example.test/api" },
47 { "panel_url", "https://provider.example.test/app" },
48 { "session_bootstrap_url", "https://provider.example.test/session/bootstrap" },
49 { "auth", {
50 { "type", "oauth2" },
51 { "metadata_url", "https://provider.example.test/.well-known/oauth-authorization-server" },
52 { "client_id", "kicad-desktop" },
53 { "scopes", nlohmann::json::array( { "openid", "profile", "parts.read" } ) }
54 } },
55 { "capabilities", {
56 { "web_ui_v1", true },
57 { "direct_downloads_v1", true },
58 { "inline_payloads_v1", true }
59 } },
60 { "max_download_bytes", 10485760 },
61 { "supported_asset_types", nlohmann::json::array( { "symbol", "footprint", "3dmodel" } ) },
62 { "parts", { { "endpoint_template", "/v1/parts/{part_id}" } } },
63 { "documentation_url", "https://provider.example.test/docs" },
64 { "terms_url", "https://provider.example.test/terms" },
65 { "privacy_url", "https://provider.example.test/privacy" }
66 };
67}
68} // namespace
69
70
71BOOST_AUTO_TEST_SUITE( RemoteProviderMetadataTests )
72
73BOOST_AUTO_TEST_CASE( ValidMetadataParses )
74{
75 wxString error;
76 std::optional<REMOTE_PROVIDER_METADATA> metadata =
77 REMOTE_PROVIDER_METADATA::FromJson( validMetadata(), schemaPath(), error );
78
79 BOOST_REQUIRE_MESSAGE( metadata.has_value(), error );
80 BOOST_CHECK_EQUAL( metadata->provider_name, wxString( "Acme Parts" ) );
81 BOOST_CHECK_EQUAL( metadata->panel_url, wxString( "https://provider.example.test/app" ) );
82 BOOST_CHECK_EQUAL( metadata->session_bootstrap_url,
83 wxString( "https://provider.example.test/session/bootstrap" ) );
84 BOOST_CHECK( metadata->web_ui_v1 );
85 BOOST_CHECK( metadata->direct_downloads_v1 );
86 BOOST_CHECK( metadata->inline_payloads_v1 );
87 BOOST_CHECK_EQUAL( metadata->auth.metadata_url,
88 wxString( "https://provider.example.test/.well-known/oauth-authorization-server" ) );
89}
90
91BOOST_AUTO_TEST_CASE( DefaultSchemaPathParsesWhenSchemaIsStaged )
92{
93 wxString error;
94 std::optional<REMOTE_PROVIDER_METADATA> metadata =
95 REMOTE_PROVIDER_METADATA::FromJson( validMetadata(), error );
96
97 BOOST_REQUIRE_MESSAGE( metadata.has_value(), error );
98}
99
100BOOST_AUTO_TEST_CASE( MissingAuthMetadataRejected )
101{
102 nlohmann::json metadata = validMetadata();
103 metadata["auth"].erase( "metadata_url" );
104
105 wxString error;
106 std::optional<REMOTE_PROVIDER_METADATA> parsed =
107 REMOTE_PROVIDER_METADATA::FromJson( metadata, schemaPath(), error );
108
109 BOOST_CHECK( !parsed.has_value() );
110 BOOST_CHECK( error.Contains( wxString( "schema validation" ) ) );
111 BOOST_CHECK( error.Contains( wxString( "metadata_url" ) ) );
112}
113
114BOOST_AUTO_TEST_CASE( InsecureProviderUrlRejectedUnlessLoopbackExplicitlyAllowed )
115{
116 nlohmann::json metadata = validMetadata();
117 metadata["api_base_url"] = "http://provider.example.test/api";
118
119 wxString error;
120 std::optional<REMOTE_PROVIDER_METADATA> parsed =
121 REMOTE_PROVIDER_METADATA::FromJson( metadata, schemaPath(), error );
122
123 BOOST_CHECK( !parsed.has_value() );
124 BOOST_CHECK( error.Contains( wxString( "api_base_url" ) ) );
125
126 metadata["allow_insecure_localhost"] = true;
127 metadata["api_base_url"] = "http://127.0.0.1:8080/api";
128 metadata["auth"]["metadata_url"] = "http://127.0.0.1:8080/.well-known/oauth-authorization-server";
129
130 parsed = REMOTE_PROVIDER_METADATA::FromJson( metadata, schemaPath(), error );
131 BOOST_REQUIRE_MESSAGE( parsed.has_value(), error );
132}
133
134BOOST_AUTO_TEST_CASE( UnsupportedCapabilityRejectedCleanly )
135{
136 nlohmann::json metadata = validMetadata();
137 metadata["capabilities"]["future_magic_v9"] = true;
138
139 wxString error;
140 std::optional<REMOTE_PROVIDER_METADATA> parsed =
141 REMOTE_PROVIDER_METADATA::FromJson( metadata, schemaPath(), error );
142
143 BOOST_CHECK( !parsed.has_value() );
144 BOOST_CHECK( error.Contains( wxString( "Unsupported provider capability" ) )
145 || error.Contains( wxString( "schema validation" ) ) );
146}
147
148BOOST_AUTO_TEST_CASE( MissingPanelUrlRejected )
149{
150 nlohmann::json metadata = validMetadata();
151 metadata.erase( "panel_url" );
152
153 wxString error;
154 std::optional<REMOTE_PROVIDER_METADATA> parsed =
155 REMOTE_PROVIDER_METADATA::FromJson( metadata, schemaPath(), error );
156
157 BOOST_CHECK( !parsed.has_value() );
158 BOOST_CHECK( error.Contains( wxString( "panel_url" ) ) );
159}
160
161BOOST_AUTO_TEST_CASE( OAuthProviderRequiresSessionBootstrapUrl )
162{
163 nlohmann::json metadata = validMetadata();
164 metadata.erase( "session_bootstrap_url" );
165
166 wxString error;
167 std::optional<REMOTE_PROVIDER_METADATA> parsed =
168 REMOTE_PROVIDER_METADATA::FromJson( metadata, schemaPath(), error );
169
170 BOOST_CHECK( !parsed.has_value() );
171 BOOST_CHECK( error.Contains( wxString( "session_bootstrap_url" ) ) );
172}
173
174BOOST_AUTO_TEST_CASE( SessionBootstrapUrlMustShareOriginWithPanelUrl )
175{
176 nlohmann::json metadata = validMetadata();
177 metadata["session_bootstrap_url"] = "https://tokens.example.test/session/bootstrap";
178
179 wxString error;
180 std::optional<REMOTE_PROVIDER_METADATA> parsed =
181 REMOTE_PROVIDER_METADATA::FromJson( metadata, schemaPath(), error );
182
183 BOOST_CHECK( !parsed.has_value() );
184 BOOST_CHECK( error.Contains( wxString( "session_bootstrap_url" ) ) );
185}
186
static std::optional< REMOTE_PROVIDER_METADATA > FromJson(const nlohmann::json &aJson, wxString &aError)
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_AUTO_TEST_SUITE(CadstarPartParser)
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(ValidMetadataParses)
BOOST_CHECK_EQUAL(result, "25.4")