20#include <boost/test/unit_test.hpp>
32wxFileName schemaPath()
34 wxFileName schemaFile = wxFileName::DirName( wxString::FromUTF8( QA_SRC_ROOT ) );
35 schemaFile.AppendDir( wxS(
"resources" ) );
36 schemaFile.AppendDir( wxS(
"schemas" ) );
37 schemaFile.SetFullName( wxS(
"kicad-remote-provider-metadata-v1.schema.json" ) );
42nlohmann::json providerMetadataJson(
const wxString& aAuthType = wxS(
"oauth2" ) )
44 nlohmann::json auth = { {
"type", aAuthType.ToStdString() } };
46 if( aAuthType == wxS(
"oauth2" ) )
48 auth[
"metadata_url"] =
"https://provider.example.test/.well-known/oauth-authorization-server";
49 auth[
"client_id"] =
"kicad-desktop";
50 auth[
"scopes"] = nlohmann::json::array( {
"openid",
"parts.read" } );
53 return nlohmann::json{
54 {
"provider_name",
"Acme Parts" },
55 {
"provider_version",
"1.0.0" },
56 {
"api_base_url",
"https://provider.example.test/api" },
57 {
"panel_url",
"https://provider.example.test/app" },
58 {
"session_bootstrap_url",
"https://provider.example.test/session/bootstrap" },
61 { {
"web_ui_v1",
true },
63 {
"direct_downloads_v1",
true },
64 {
"inline_payloads_v1",
true } } },
65 {
"max_download_bytes", 10485760 },
66 {
"supported_asset_types", nlohmann::json::array( {
"symbol",
"footprint",
"3dmodel" } ) },
67 {
"parts", { {
"endpoint_template",
"/v1/parts/{part_id}" } } }
75 std::optional<REMOTE_PROVIDER_METADATA> metadata =
78 if( !metadata.has_value() )
79 throw std::runtime_error( error.ToStdString() );
85nlohmann::json authServerMetadataJson()
87 return nlohmann::json{ {
"issuer",
"https://provider.example.test" },
88 {
"authorization_endpoint",
"https://provider.example.test/oauth/authorize" },
89 {
"token_endpoint",
"https://provider.example.test/oauth/token" },
90 {
"revocation_endpoint",
"https://provider.example.test/oauth/revoke" } };
93nlohmann::json manifestJson()
95 return nlohmann::json{
96 {
"part_id",
"acme-res-10k" },
97 {
"display_name",
"10k Resistor" },
98 {
"summary",
"10k 0603 thick film resistor" },
99 {
"license",
"CC-BY-4.0" },
100 {
"assets", nlohmann::json::array(
101 { { {
"asset_type",
"symbol" },
102 {
"name",
"acme-res-10k.kicad_sym" },
103 {
"content_type",
"application/x-kicad-symbol" },
104 {
"size_bytes", 2048 },
105 {
"sha256",
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" },
106 {
"download_url",
"https://provider.example.test/downloads/acme-res-10k.kicad_sym" },
107 {
"required",
true } },
108 { {
"asset_type",
"footprint" },
109 {
"name",
"R_0603.pretty" },
110 {
"content_type",
"application/x-kicad-footprint" },
111 {
"size_bytes", 4096 },
112 {
"sha256",
"abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789" },
113 {
"download_url",
"https://provider.example.test/downloads/R_0603.pretty" },
114 {
"required",
false } } } ) }
119wxString dumpJson(
const nlohmann::json& aJson )
121 return wxString::FromUTF8( aJson.dump().c_str() );
123struct BUILD_DIR_FIXTURE
127 m_wasSet = wxGetEnv( wxS(
"KICAD_RUN_FROM_BUILD_DIR" ), &m_oldValue );
130 wxSetEnv( wxS(
"KICAD_RUN_FROM_BUILD_DIR" ), wxS(
"1" ) );
136 wxUnsetEnv( wxS(
"KICAD_RUN_FROM_BUILD_DIR" ) );
146BOOST_FIXTURE_TEST_SUITE( RemoteProviderClientTests, BUILD_DIR_FIXTURE )
150 std::vector<wxString> requestedUrls;
156 wxUnusedVar( aError );
157 requestedUrls.push_back( aRequest.
url );
159 aResponse.
body = dumpJson( providerMetadataJson() );
166 BOOST_REQUIRE( client.DiscoverProvider( wxString(
"https://provider.example.test" ), metadata, error ) );
169 wxString(
"https://provider.example.test/.well-known/kicad-remote-provider" ) );
181 wxUnusedVar( aError );
183 wxString(
"https://provider.example.test/.well-known/oauth-authorization-server" ) );
185 aResponse.
body = dumpJson( authServerMetadataJson() );
192 BOOST_REQUIRE( client.FetchOAuthServerMetadata( metadata, authMetadata, error ) );
194 wxString(
"https://provider.example.test/oauth/authorize" ) );
195 BOOST_CHECK_EQUAL( authMetadata.token_endpoint, wxString(
"https://provider.example.test/oauth/token" ) );
206 wxUnusedVar( aError );
209 wxString(
"https://provider.example.test/api/v1/parts/acme-res-10k" ) );
211 aResponse.
body = dumpJson( manifestJson() );
218 BOOST_REQUIRE( client.FetchManifest( metadata, wxString(
"acme-res-10k" ), wxString(), manifest, error ) );
220 BOOST_REQUIRE_EQUAL( manifest.assets.size(), 2U );
223 wxString(
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" ) );
224 BOOST_CHECK( manifest.assets.front().required );
232 oauth.
token_endpoint = wxString(
"https://provider.example.test/oauth/token" );
238 wxUnusedVar( aError );
241 BOOST_CHECK( aRequest.
body.Contains( wxString(
"grant_type=authorization_code" ) ) );
242 BOOST_CHECK( aRequest.
body.Contains( wxString(
"code=test-code" ) ) );
244 aResponse.
body = dumpJson( {
245 {
"access_token",
"access-123" },
246 {
"refresh_token",
"refresh-123" },
247 {
"token_type",
"Bearer" },
248 {
"scope",
"openid parts.read" },
249 {
"expires_in", 3600 }
256 session.redirect_uri = wxString(
"http://127.0.0.1:9000/oauth/callback" );
257 session.code_verifier = wxString(
"verifier" );
261 BOOST_REQUIRE( client.ExchangeAuthorizationCode( oauth, session, wxString(
"test-code" ), tokens, error ) );
270 oauth.
token_endpoint = wxString(
"https://provider.example.test/oauth/token" );
276 wxUnusedVar( aError );
277 BOOST_CHECK( aRequest.
body.Contains( wxString(
"grant_type=refresh_token" ) ) );
278 BOOST_CHECK( aRequest.
body.Contains( wxString(
"refresh_token=refresh-123" ) ) );
280 aResponse.
body = dumpJson( {
281 {
"access_token",
"access-456" },
282 {
"refresh_token",
"refresh-456" },
283 {
"token_type",
"Bearer" },
284 {
"scope",
"openid parts.read" },
285 {
"expires_in", 3600 }
292 BOOST_REQUIRE( client.RefreshAccessToken( oauth, wxString(
"kicad-desktop" ),
293 wxString(
"refresh-123" ), tokens, error ) );
307 wxUnusedVar( aError );
308 BOOST_CHECK( aRequest.
body.Contains( wxString(
"token=access-123" ) ) );
310 aResponse.
body = wxString(
"{}" );
315 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")