20#include <boost/test/unit_test.hpp>
28#include <wx/filename.h>
33wxFileName schemaPath()
35 wxFileName schemaFile = wxFileName::DirName( wxString::FromUTF8( QA_SRC_ROOT ) );
36 schemaFile.AppendDir( wxS(
"resources" ) );
37 schemaFile.AppendDir( wxS(
"schemas" ) );
38 schemaFile.SetFullName( wxS(
"kicad-remote-provider-metadata-v1.schema.json" ) );
43nlohmann::json providerMetadataJson(
const wxString& aAuthType = wxS(
"oauth2" ) )
45 nlohmann::json auth = { {
"type", aAuthType.ToStdString() } };
47 if( aAuthType == wxS(
"oauth2" ) )
49 auth[
"metadata_url"] =
"https://provider.example.test/.well-known/oauth-authorization-server";
50 auth[
"client_id"] =
"kicad-desktop";
51 auth[
"scopes"] = nlohmann::json::array( {
"openid",
"parts.read" } );
54 return nlohmann::json{
55 {
"provider_name",
"Acme Parts" },
56 {
"provider_version",
"1.0.0" },
57 {
"api_base_url",
"https://provider.example.test/api" },
58 {
"panel_url",
"https://provider.example.test/app" },
59 {
"session_bootstrap_url",
"https://provider.example.test/session/bootstrap" },
62 { {
"web_ui_v1",
true },
64 {
"direct_downloads_v1",
true },
65 {
"inline_payloads_v1",
true } } },
66 {
"max_download_bytes", 10485760 },
67 {
"supported_asset_types", nlohmann::json::array( {
"symbol",
"footprint",
"3dmodel" } ) },
68 {
"parts", { {
"endpoint_template",
"/v1/parts/{part_id}" } } }
76 std::optional<REMOTE_PROVIDER_METADATA> metadata =
79 if( !metadata.has_value() )
80 throw std::runtime_error( error.ToStdString() );
86nlohmann::json authServerMetadataJson()
88 return nlohmann::json{ {
"issuer",
"https://provider.example.test" },
89 {
"authorization_endpoint",
"https://provider.example.test/oauth/authorize" },
90 {
"token_endpoint",
"https://provider.example.test/oauth/token" },
91 {
"revocation_endpoint",
"https://provider.example.test/oauth/revoke" } };
94nlohmann::json manifestJson()
96 return nlohmann::json{
97 {
"part_id",
"acme-res-10k" },
98 {
"display_name",
"10k Resistor" },
99 {
"summary",
"10k 0603 thick film resistor" },
100 {
"license",
"CC-BY-4.0" },
101 {
"assets", nlohmann::json::array(
102 { { {
"asset_type",
"symbol" },
103 {
"name",
"acme-res-10k.kicad_sym" },
104 {
"content_type",
"application/x-kicad-symbol" },
105 {
"size_bytes", 2048 },
106 {
"sha256",
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" },
107 {
"download_url",
"https://provider.example.test/downloads/acme-res-10k.kicad_sym" },
108 {
"required",
true } },
109 { {
"asset_type",
"footprint" },
110 {
"name",
"R_0603.pretty" },
111 {
"content_type",
"application/x-kicad-footprint" },
112 {
"size_bytes", 4096 },
113 {
"sha256",
"abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789" },
114 {
"download_url",
"https://provider.example.test/downloads/R_0603.pretty" },
115 {
"required",
false } } } ) }
120wxString dumpJson(
const nlohmann::json& aJson )
122 return wxString::FromUTF8( aJson.dump().c_str() );
124struct BUILD_DIR_FIXTURE
128 m_runFromBuildDirWasSet = wxGetEnv( wxS(
"KICAD_RUN_FROM_BUILD_DIR" ), &m_oldRunFromBuildDir );
133 wxUnsetEnv( wxS(
"KICAD_RUN_FROM_BUILD_DIR" ) );
135 wxFileName resourcesDir = wxFileName::DirName( wxString::FromUTF8( QA_SRC_ROOT ) );
136 resourcesDir.AppendDir( wxS(
"resources" ) );
137 m_stockDataHomeWasSet = wxGetEnv( wxS(
"KICAD_STOCK_DATA_HOME" ), &m_oldStockDataHome );
138 wxSetEnv( wxS(
"KICAD_STOCK_DATA_HOME" ), resourcesDir.GetPath() );
140 if( !m_runFromBuildDirWasSet )
141 wxSetEnv( wxS(
"KICAD_RUN_FROM_BUILD_DIR" ), wxS(
"1" ) );
147 if( m_runFromBuildDirWasSet )
148 wxSetEnv( wxS(
"KICAD_RUN_FROM_BUILD_DIR" ), m_oldRunFromBuildDir );
150 wxUnsetEnv( wxS(
"KICAD_RUN_FROM_BUILD_DIR" ) );
153 if( m_stockDataHomeWasSet )
154 wxSetEnv( wxS(
"KICAD_STOCK_DATA_HOME" ), m_oldStockDataHome );
156 wxUnsetEnv( wxS(
"KICAD_STOCK_DATA_HOME" ) );
160 bool m_runFromBuildDirWasSet =
false;
161 wxString m_oldRunFromBuildDir;
163 bool m_stockDataHomeWasSet =
false;
164 wxString m_oldStockDataHome;
171BOOST_FIXTURE_TEST_SUITE( RemoteProviderClientTests, BUILD_DIR_FIXTURE )
175 std::vector<wxString> requestedUrls;
181 wxUnusedVar( aError );
182 requestedUrls.push_back( aRequest.
url );
184 aResponse.
body = dumpJson( providerMetadataJson() );
191 BOOST_REQUIRE( client.DiscoverProvider( wxString(
"https://provider.example.test" ), metadata, error ) );
194 wxString(
"https://provider.example.test/.well-known/kicad-remote-provider" ) );
206 wxUnusedVar( aError );
208 wxString(
"https://provider.example.test/.well-known/oauth-authorization-server" ) );
210 aResponse.
body = dumpJson( authServerMetadataJson() );
217 BOOST_REQUIRE( client.FetchOAuthServerMetadata( metadata, authMetadata, error ) );
219 wxString(
"https://provider.example.test/oauth/authorize" ) );
220 BOOST_CHECK_EQUAL( authMetadata.token_endpoint, wxString(
"https://provider.example.test/oauth/token" ) );
231 wxUnusedVar( aError );
234 wxString(
"https://provider.example.test/api/v1/parts/acme-res-10k" ) );
236 aResponse.
body = dumpJson( manifestJson() );
243 BOOST_REQUIRE( client.FetchManifest( metadata, wxString(
"acme-res-10k" ), wxString(), manifest, error ) );
245 BOOST_REQUIRE_EQUAL( manifest.assets.size(), 2U );
248 wxString(
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" ) );
249 BOOST_CHECK( manifest.assets.front().required );
257 oauth.
token_endpoint = wxString(
"https://provider.example.test/oauth/token" );
263 wxUnusedVar( aError );
266 BOOST_CHECK( aRequest.
body.Contains( wxString(
"grant_type=authorization_code" ) ) );
267 BOOST_CHECK( aRequest.
body.Contains( wxString(
"code=test-code" ) ) );
269 aResponse.
body = dumpJson( {
270 {
"access_token",
"access-123" },
271 {
"refresh_token",
"refresh-123" },
272 {
"token_type",
"Bearer" },
273 {
"scope",
"openid parts.read" },
274 {
"expires_in", 3600 }
281 session.redirect_uri = wxString(
"http://127.0.0.1:9000/oauth/callback" );
282 session.code_verifier = wxString(
"verifier" );
286 BOOST_REQUIRE( client.ExchangeAuthorizationCode( oauth, session, wxString(
"test-code" ), tokens, error ) );
295 oauth.
token_endpoint = wxString(
"https://provider.example.test/oauth/token" );
301 wxUnusedVar( aError );
302 BOOST_CHECK( aRequest.
body.Contains( wxString(
"grant_type=refresh_token" ) ) );
303 BOOST_CHECK( aRequest.
body.Contains( wxString(
"refresh_token=refresh-123" ) ) );
305 aResponse.
body = dumpJson( {
306 {
"access_token",
"access-456" },
307 {
"refresh_token",
"refresh-456" },
308 {
"token_type",
"Bearer" },
309 {
"scope",
"openid parts.read" },
310 {
"expires_in", 3600 }
317 BOOST_REQUIRE( client.RefreshAccessToken( oauth, wxString(
"kicad-desktop" ),
318 wxString(
"refresh-123" ), tokens, error ) );
332 wxUnusedVar( aError );
333 BOOST_CHECK( aRequest.
body.Contains( wxString(
"token=access-123" ) ) );
335 aResponse.
body = wxString(
"{}" );
340 BOOST_CHECK( client.RevokeToken( oauth, wxString(
"kicad-desktop" ), wxString(
"access-123" ), error ) );
REMOTE_PROVIDER_HTTP_METHOD method
BOOST_AUTO_TEST_CASE(HorizontalAlignment)
BOOST_REQUIRE(intersection.has_value()==c.ExpectedIntersection.has_value())
BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_CASE(DiscoveryFetchesWellKnownMetadata)
BOOST_CHECK_EQUAL(result, "25.4")