From c65dfc797c182bb91ac921636406c6b5ed1b89c1 Mon Sep 17 00:00:00 2001 From: Dave Reisner Date: Sat, 10 Aug 2024 21:02:38 -0400 Subject: [PATCH] Migrate info and search verbs to new REST API This lets us drop the notion that a single RpcRequest can result in multiple HTTP requests, greatly simplifying our dispatch logic. --- src/aur/aur.cc | 72 +++++++++++++++++++-------------- src/aur/aur.hh | 6 ++- src/aur/request.cc | 58 +++++---------------------- src/aur/request.hh | 82 +++++++++++++++++++------------------- src/aur/request_test.cc | 76 ++++++----------------------------- tests/fakeaur/server.py | 40 +++++++++++++------ tests/test_clone.py | 11 ++--- tests/test_outdated.py | 8 +--- tests/test_raw_query.py | 14 +++---- tests/test_regex_search.py | 6 +-- tests/test_search.py | 8 ++-- tests/test_show.py | 9 ++--- 12 files changed, 163 insertions(+), 227 deletions(-) diff --git a/src/aur/aur.cc b/src/aur/aur.cc index 514923a..a29ef88 100644 --- a/src/aur/aur.cc +++ b/src/aur/aur.cc @@ -36,6 +36,8 @@ class AurImpl : public Aur { void QueueRawRequest(const HttpRequest& request, const RawResponseCallback& callback) override; + void QueueRawRequest(const RpcRequest& request, + const RawResponseCallback& callback) override; void QueueCloneRequest(const CloneRequest& request, const CloneResponseCallback& callback) override; @@ -52,6 +54,10 @@ class AurImpl : public Aur { void QueueHttpRequest(const HttpRequest& request, const ResponseHandlerType::CallbackType& callback); + template + void QueueRpcRequest(const RpcRequest& request, + const ResponseHandlerType::CallbackType& callback); + int FinishRequest(CURL* curl, CURLcode result, bool dispatch_callback); int FinishRequest(sd_event_source* source); @@ -498,36 +504,39 @@ template void AurImpl::QueueHttpRequest( const HttpRequest& request, const ResponseHandlerType::CallbackType& callback) { - for (const auto& r : request.Build(options_.baseurl)) { - auto* curl = curl_easy_init(); - auto* handler = new ResponseHandlerType(this, callback); - - using RH = ResponseHandler; - curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2); - curl_easy_setopt(curl, CURLOPT_URL, r.c_str()); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &RH::BodyCallback); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, handler); - curl_easy_setopt(curl, CURLOPT_PRIVATE, handler); - curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, handler->error_buffer.data()); - curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""); - curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L); - curl_easy_setopt(curl, CURLOPT_USERAGENT, options_.useragent.c_str()); - - switch (debug_level_) { - case DebugLevel::NONE: - break; - case DebugLevel::REQUESTS: - curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, &RH::DebugCallback); - curl_easy_setopt(curl, CURLOPT_DEBUGDATA, &debug_stream_); - [[fallthrough]]; - case DebugLevel::VERBOSE_STDERR: - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); - break; - } + auto* curl = curl_easy_init(); + auto* handler = new ResponseHandlerType(this, callback); + + using RH = ResponseHandler; + curl_easy_setopt(curl, CURLOPT_URL, request.Url(options_.baseurl).c_str()); + curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2); + curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, ""); + curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 10L); + curl_easy_setopt(curl, CURLOPT_USERAGENT, options_.useragent.c_str()); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &RH::BodyCallback); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, handler); + curl_easy_setopt(curl, CURLOPT_PRIVATE, handler); + curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, handler->error_buffer.data()); + + if (request.command() == RpcRequest::Command::POST) { + curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, request.Payload().c_str()); + } - curl_multi_add_handle(curl_multi_, curl); - active_requests_.emplace(curl); + switch (debug_level_) { + case DebugLevel::NONE: + break; + case DebugLevel::REQUESTS: + curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, + &ResponseHandler::DebugCallback); + curl_easy_setopt(curl, CURLOPT_DEBUGDATA, &debug_stream_); + [[fallthrough]]; + case DebugLevel::VERBOSE_STDERR: + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + break; } + + curl_multi_add_handle(curl_multi_, curl); + active_requests_.emplace(curl); } // static @@ -561,7 +570,7 @@ void AurImpl::QueueCloneRequest(const CloneRequest& request, } if (pid == 0) { - const auto url = request.Build(options_.baseurl)[0]; + const auto url = request.Url(options_.baseurl); std::vector cmd; if (update) { @@ -605,6 +614,11 @@ void AurImpl::QueueRawRequest(const HttpRequest& request, QueueHttpRequest(request, callback); } +void AurImpl::QueueRawRequest(const RpcRequest& request, + const RawResponseCallback& callback) { + QueueHttpRequest(request, callback); +} + void AurImpl::QueueRpcRequest(const RpcRequest& request, const RpcResponseCallback& callback) { QueueHttpRequest(request, callback); diff --git a/src/aur/aur.hh b/src/aur/aur.hh index a22b818..9014f9b 100644 --- a/src/aur/aur.hh +++ b/src/aur/aur.hh @@ -51,8 +51,8 @@ class Aur { Aur(Aur&&) = default; Aur& operator=(Aur&&) = default; - // Asynchronously issue an RPC request. The callback will be invoked when the - // call completes. + // Asynchronously issue an RPC request using the REST API. The callback will + // be invoked when the call completes. virtual void QueueRpcRequest(const RpcRequest& request, const RpcResponseCallback& callback) = 0; @@ -60,6 +60,8 @@ class Aur { // call completes. virtual void QueueRawRequest(const HttpRequest& request, const RawResponseCallback& callback) = 0; + virtual void QueueRawRequest(const RpcRequest& request, + const RawResponseCallback& callback) = 0; // Clone a git repository. virtual void QueueCloneRequest(const CloneRequest& request, diff --git a/src/aur/request.cc b/src/aur/request.cc index 12191a8..59feca2 100644 --- a/src/aur/request.cc +++ b/src/aur/request.cc @@ -28,53 +28,17 @@ void QueryParamFormatter(std::string* out, const HttpRequest::QueryParam& kv) { } // namespace -void RpcRequest::AddArg(std::string_view key, std::string_view value) { - args_.emplace_back(key, value); +std::string RpcRequest::Url(std::string_view baseurl) const { + return absl::StrCat(baseurl, endpoint_); } -std::vector RpcRequest::Build(std::string_view baseurl) const { - const auto next_span = [&](std::string_view s) -> std::string_view { - // No chopping needed. - if (s.size() <= approx_max_length_) { - return s; - } - - // Try to chop at the final ampersand before the cutoff length. - auto n = s.substr(0, approx_max_length_).rfind('&'); - if (n != std::string_view::npos) { - return s.substr(0, n); - } - - // We found a single arg which is Too Damn Long. Look for the ampersand just - // after the length limit and use all of it. - n = s.substr(approx_max_length_).find('&'); - if (n != std::string_view::npos) { - return s.substr(0, n + approx_max_length_); - } - - // We're at the end of the querystring and have no place to chop. - return s; - }; - - const auto qs = absl::StrJoin(args_, "&", &QueryParamFormatter); - std::string_view sv(qs); - - std::vector requests; - while (!sv.empty()) { - const auto span = next_span(sv); - - requests.push_back( - absl::StrCat(baseurl, "/rpc?", base_querystring_, "&", span)); - sv.remove_prefix(std::min(sv.length(), span.length() + 1)); - } - - return requests; +void RpcRequest::AddArg(std::string key, std::string value) { + params_.push_back({std::move(key), std::move(value)}); } -RpcRequest::RpcRequest(const HttpRequest::QueryParams& base_params, - size_type approx_max_length) - : base_querystring_(absl::StrJoin(base_params, "&", &QueryParamFormatter)), - approx_max_length_(approx_max_length) {} +std::string RpcRequest::Payload() const { + return absl::StrJoin(params_, "&", QueryParamFormatter); +} // static RawRequest RawRequest::ForSourceFile(const Package& package, @@ -83,12 +47,12 @@ RawRequest RawRequest::ForSourceFile(const Package& package, "?h=", UrlEscape(package.pkgbase))); } -std::vector RawRequest::Build(std::string_view baseurl) const { - return {absl::StrCat(baseurl, urlpath_)}; +std::string RawRequest::Url(std::string_view baseurl) const { + return absl::StrCat(baseurl, urlpath_); } -std::vector CloneRequest::Build(std::string_view baseurl) const { - return {absl::StrCat(baseurl, "/", reponame_)}; +std::string CloneRequest::Url(std::string_view baseurl) const { + return absl::StrCat(baseurl, "/", reponame_); } } // namespace aur diff --git a/src/aur/request.hh b/src/aur/request.hh index 8fc1a39..f2a96b9 100644 --- a/src/aur/request.hh +++ b/src/aur/request.hh @@ -6,6 +6,7 @@ #include #include +#include "absl/strings/str_format.h" #include "package.hh" namespace aur { @@ -15,13 +16,42 @@ class Request { public: virtual ~Request() = default; - virtual std::vector Build(std::string_view baseurl) const = 0; + virtual std::string Url(std::string_view baseurl) const = 0; }; class HttpRequest : public Request { public: + enum class Command : int8_t { + GET, + POST, + }; + using QueryParam = std::pair; using QueryParams = std::vector; + + explicit HttpRequest(Command command) : command_(command) {} + + Command command() const { return command_; } + + virtual std::string Payload() const = 0; + + protected: + Command command_; +}; + +class RpcRequest : public HttpRequest { + public: + RpcRequest(Command command, std::string endpoint) + : HttpRequest(command), endpoint_(std::move(endpoint)) {} + + std::string Url(std::string_view baseurl) const override; + std::string Payload() const override; + + void AddArg(std::string key, std::string value); + + private: + std::string endpoint_; + QueryParams params_; }; // A class describing a GET request for an arbitrary URL on the AUR. @@ -30,7 +60,8 @@ class RawRequest : public HttpRequest { static RawRequest ForSourceFile(const Package& package, std::string_view filename); - explicit RawRequest(std::string urlpath) : urlpath_(std::move(urlpath)) {} + explicit RawRequest(std::string urlpath) + : HttpRequest(HttpRequest::Command::GET), urlpath_(std::move(urlpath)) {} RawRequest(const RawRequest&) = delete; RawRequest& operator=(const RawRequest&) = delete; @@ -38,7 +69,8 @@ class RawRequest : public HttpRequest { RawRequest(RawRequest&&) = default; RawRequest& operator=(RawRequest&&) = default; - std::vector Build(std::string_view baseurl) const override; + std::string Url(std::string_view baseurl) const override; + std::string Payload() const override { return std::string(); } private: std::string urlpath_; @@ -58,40 +90,12 @@ class CloneRequest : public Request { const std::string& reponame() const { return reponame_; } - std::vector Build(std::string_view baseurl) const override; + std::string Url(std::string_view baseurl) const override; private: std::string reponame_; }; -// A base class describing a GET request to the RPC endpoint of the AUR. -class RpcRequest : public HttpRequest { - public: - using size_type = std::string_view::size_type; - - // Upper limit on aur.archlinux.org seems to be somewhere around 8k. - static constexpr size_type kMaxUriLength = 8000; - - RpcRequest(const HttpRequest::QueryParams& base_params, - size_type approx_max_length = kMaxUriLength); - - RpcRequest(const RpcRequest&) = delete; - RpcRequest& operator=(const RpcRequest&) = delete; - - RpcRequest(RpcRequest&&) = default; - RpcRequest& operator=(RpcRequest&&) = default; - - std::vector Build(std::string_view baseurl) const override; - - void AddArg(std::string_view key, std::string_view value); - - private: - std::string base_querystring_; - size_type approx_max_length_; - - HttpRequest::QueryParams args_; -}; - class InfoRequest : public RpcRequest { public: explicit InfoRequest(const std::vector& args) : InfoRequest() { @@ -106,9 +110,9 @@ class InfoRequest : public RpcRequest { InfoRequest(InfoRequest&&) = default; InfoRequest& operator=(InfoRequest&&) = default; - InfoRequest() : RpcRequest({{"v", "5"}, {"type", "info"}}) {} + InfoRequest() : RpcRequest(HttpRequest::Command::POST, "/rpc/v5/info") {} - void AddArg(std::string_view arg) { RpcRequest::AddArg("arg[]", arg); } + void AddArg(std::string arg) { RpcRequest::AddArg("arg[]", std::move(arg)); } }; class SearchRequest : public RpcRequest { @@ -178,13 +182,9 @@ class SearchRequest : public RpcRequest { } SearchRequest(SearchBy by, std::string_view arg) - : RpcRequest({ - {"v", "5"}, - {"type", "search"}, - {"by", SearchByToString(by)}, - }) { - AddArg("arg", arg); - } + : RpcRequest(HttpRequest::Command::GET, + absl::StrFormat("/rpc/v5/search/%s?by=%s", arg, + SearchByToString(by))) {} SearchRequest(const SearchRequest&) = delete; SearchRequest& operator=(const SearchRequest&) = delete; diff --git a/src/aur/request_test.cc b/src/aur/request_test.cc index 22991f9..c068d1c 100644 --- a/src/aur/request_test.cc +++ b/src/aur/request_test.cc @@ -17,11 +17,11 @@ TEST(RequestTest, BuildsInfoRequests) { request.AddArg("derp"); - const auto urls = request.Build(kBaseUrl); - ASSERT_EQ(urls.size(), 1); + const auto url = request.Url(kBaseUrl); + EXPECT_THAT(url, AllOf(EndsWith("/rpc/v5/info"))); - EXPECT_THAT(urls[0], AllOf(StartsWith(kBaseUrl), HasSubstr("v=5"), - HasSubstr("type=info"), HasSubstr("arg[]=derp"))); + const auto payload = request.Payload(); + EXPECT_EQ(payload, "arg[]=derp"); } TEST(RequestTest, UrlEncodesParameterValues) { @@ -29,73 +29,25 @@ TEST(RequestTest, UrlEncodesParameterValues) { request.AddArg("c++"); - const auto urls = request.Build(kBaseUrl); - EXPECT_THAT(urls[0], HasSubstr("arg[]=c%2B%2B")); -} - -TEST(RequestTest, BuildsMultipleUrlsForLongRequests) { - aur::RpcRequest request({{"v", "5"}}, 100); - - const std::string longarg(14, 'a'); - for (int i = 0; i < 10; ++i) { - request.AddArg("arg[]", longarg); - } - - // Builds more than one URL because we go over the limit. - const auto urls = request.Build(kBaseUrl); - ASSERT_EQ(urls.size(), 3); - - const auto arg = "&arg[]=" + longarg; - for (const auto& url : urls) { - EXPECT_THAT( - url, - AllOf( - // URLs aren't truncated - EndsWith(arg), - // We've trimmed things correctly in chopping up the querystring - Not(HasSubstr("&&")))); - } -} - -TEST(RequestTest, BuildsUrlForArgLongerThanMaxLen) { - aur::RpcRequest request({{"v", "5"}}, 10); - - // At the limit - request.AddArg("arg[]", "fooo"); - // Consecutive over the limit - request.AddArg("arg[]", "1234567890"); - request.AddArg("arg[]", "0987654321"); - // Under the limit - request.AddArg("arg[]", "bar"); - // Over the limit at the end - request.AddArg("arg[]", "0987654321"); - - const auto urls = request.Build(kBaseUrl); - ASSERT_EQ(urls.size(), 5); - EXPECT_THAT(urls[0], EndsWith("arg[]=fooo")); - EXPECT_THAT(urls[1], EndsWith("arg[]=1234567890")); - EXPECT_THAT(urls[2], EndsWith("arg[]=0987654321")); - EXPECT_THAT(urls[3], EndsWith("arg[]=bar")); - EXPECT_THAT(urls[4], EndsWith("arg[]=0987654321")); + const auto payload = request.Payload(); + EXPECT_EQ(payload, "arg[]=c%2B%2B"); } TEST(RequestTest, BuildsSearchRequests) { aur::SearchRequest request(aur::SearchRequest::SearchBy::MAINTAINER, "foo"); - const auto urls = request.Build(kBaseUrl); - ASSERT_EQ(urls.size(), 1); + const std::string url = request.Url(kBaseUrl); - EXPECT_THAT(urls[0], AllOf(HasSubstr("v=5"), HasSubstr("by=maintainer"), - HasSubstr("type=search"), HasSubstr("arg=foo"))); + EXPECT_THAT(url, + AllOf(testing::EndsWith("/rpc/v5/search/foo?by=maintainer"))); } TEST(RequestTest, BuildsRawRequests) { aur::RawRequest request("/foo/bar/baz"); - const auto urls = request.Build(kBaseUrl); - ASSERT_EQ(urls.size(), 1); + const auto url = request.Url(kBaseUrl); - EXPECT_EQ(urls[0], std::string(kBaseUrl) + "/foo/bar/baz"); + EXPECT_EQ(url, std::string(kBaseUrl) + "/foo/bar/baz"); } TEST(RequestTest, UrlForSourceFileEscapesReponame) { @@ -103,7 +55,7 @@ TEST(RequestTest, UrlForSourceFileEscapesReponame) { p.pkgbase = "libc++"; auto request = aur::RawRequest::ForSourceFile(p, "PKGBUILD"); - auto url = request.Build(kBaseUrl)[0]; + auto url = request.Url(kBaseUrl); EXPECT_THAT(url, EndsWith("/PKGBUILD?h=libc%2B%2B")); } @@ -115,9 +67,7 @@ TEST(RequestTest, BuildsCloneRequests) { ASSERT_EQ(request.reponame(), kReponame); - const auto urls = request.Build(kBaseUrl); - ASSERT_EQ(urls.size(), 1); + const auto url = request.Url(kBaseUrl); - const auto& url = urls[0]; EXPECT_EQ(url, std::string(kBaseUrl) + "/" + kReponame); } diff --git a/tests/fakeaur/server.py b/tests/fakeaur/server.py index 9be9589..d5261ff 100644 --- a/tests/fakeaur/server.py +++ b/tests/fakeaur/server.py @@ -29,7 +29,19 @@ def do_GET(self): for path, handler in handlers.items(): if url.path.startswith(path): - return handler(url) + return handler('GET', url) + + return self.respond(status_code=404) + + def do_POST(self): + handlers = { + '/rpc': self.handle_rpc, + } + url = urllib.parse.urlparse(self.path) + + for path, handler in handlers.items(): + if url.path.startswith(path): + return handler('POST', url) return self.respond(status_code=404) @@ -92,20 +104,24 @@ def handle_rpc_search(self, arg, by): return self.respond(response=reply) - def handle_rpc(self, url): - queryparams = urllib.parse.parse_qs(url.query) - - rpc_type = self.last_of(queryparams.get('type', None)) - if rpc_type == 'info': + def handle_rpc(self, command, url): + if command == 'GET': + queryparams = urllib.parse.parse_qs(url.query) + else: + content_len = int(self.headers.get('Content-Length')) + queryparams = urllib.parse.parse_qs( + self.rfile.read(content_len).decode()) + + if url.path.startswith('/rpc/v5/search'): + return self.handle_rpc_search( + url.path.rsplit('/')[-1], self.last_of(queryparams.get('by'))) + elif url.path.startswith('/rpc/v5/info'): return self.handle_rpc_info(set(queryparams.get('arg[]', []))) - elif rpc_type == 'search': - return self.handle_rpc_search(self.last_of(queryparams.get('arg')), - self.last_of(queryparams.get('by'))) else: - return self.respond(response=self.make_json_error_reply( + return self.respond(response=self.make_error_reply( 'Incorrect request type specified.')) - def handle_download(self, url): + def handle_download(self, command, url): pkgname = os.path.basename(url.path).split('.')[0] # error injection for specific package name @@ -128,7 +144,7 @@ def handle_download(self, url): return self.respond(headers=headers, response=response) - def handle_source_file(self, url): + def handle_source_file(self, command, url): queryparams = urllib.parse.parse_qs(url.query) pkgname = self.last_of(queryparams.get('h')) diff --git a/tests/test_clone.py b/tests/test_clone.py index 06398c8..d762d8b 100644 --- a/tests/test_clone.py +++ b/tests/test_clone.py @@ -12,8 +12,7 @@ def testCloneSingle(self): self.assertEqual(r.process.returncode, 0) self.assertPkgbuildExists('auracle-git') - self.assertCountEqual(r.request_uris, - ['/rpc?v=5&type=info&arg[]=auracle-git']) + self.assertCountEqual(r.request_uris, ['/rpc/v5/info']) def testCloneNotFound(self): r = self.Auracle(['clone', 'packagenotfound']) @@ -26,9 +25,7 @@ def testCloneMultiple(self): self.assertPkgbuildExists('auracle-git') self.assertPkgbuildExists('pkgfile-git') - self.assertCountEqual( - r.request_uris, - ['/rpc?v=5&type=info&arg[]=auracle-git&arg[]=pkgfile-git']) + self.assertCountEqual(r.request_uris, ['/rpc/v5/info']) def testCloneRecursive(self): r = self.Auracle(['clone', '-r', 'auracle-git']) @@ -37,7 +34,7 @@ def testCloneRecursive(self): self.assertPkgbuildExists('nlohmann-json') self.assertGreater(len(r.request_uris), 1) - self.assertIn('/rpc?v=5&type=info&arg[]=auracle-git', r.request_uris) + self.assertIn('/rpc/v5/info', r.request_uris) def testCloneRecursiveWithRestrictedDeps(self): r = self.Auracle( @@ -47,7 +44,7 @@ def testCloneRecursiveWithRestrictedDeps(self): self.assertPkgbuildNotExists('nlohmann-json') self.assertGreater(len(r.request_uris), 1) - self.assertIn('/rpc?v=5&type=info&arg[]=auracle-git', r.request_uris) + self.assertIn('/rpc/v5/info', r.request_uris) def testCloneUpdatesExistingCheckouts(self): # Package doesn't initially exist, expect a clone. diff --git a/tests/test_outdated.py b/tests/test_outdated.py index 25ba7f4..098fa61 100644 --- a/tests/test_outdated.py +++ b/tests/test_outdated.py @@ -12,17 +12,13 @@ def testOutdatedFindsPackagesNeedingUpgrade(self): self.assertListEqual(r.process.stdout.decode().strip().splitlines(), ['auracle-git', 'pkgfile-git']) - # TODO: build this dynamically from the filesystem? - self.assertCountEqual(r.request_uris, [ - '/rpc?v=5&type=info&arg[]=auracle-git&arg[]=ocaml&arg[]=pkgfile-git' - ]) + self.assertCountEqual(r.request_uris, ['/rpc/v5/info']) def testOutdatedFiltersUpdatesToArgs(self): r = self.Auracle(['outdated', 'auracle-git']) self.assertEqual(0, r.process.returncode) - self.assertCountEqual(['/rpc?v=5&type=info&arg[]=auracle-git'], - r.request_uris) + self.assertCountEqual(['/rpc/v5/info'], r.request_uris) def testExitsNonZeroWithoutUpgrades(self): r = self.Auracle(['outdated', '--quiet', 'ocaml']) diff --git a/tests/test_raw_query.py b/tests/test_raw_query.py index 8c102b0..626bfa9 100644 --- a/tests/test_raw_query.py +++ b/tests/test_raw_query.py @@ -17,9 +17,7 @@ def testRawInfo(self): names = (r['Name'] for r in parsed['results']) self.assertIn('auracle-git', names) - self.assertCountEqual([ - '/rpc?v=5&type=info&arg[]=auracle-git', - ], r.request_uris) + self.assertCountEqual(['/rpc/v5/info'], r.request_uris) def testRawSearch(self): r = self.Auracle(['rawsearch', 'aura']) @@ -32,7 +30,7 @@ def testRawSearch(self): self.assertIn('auracle-git', names) self.assertCountEqual([ - '/rpc?v=5&type=search&by=name-desc&arg=aura', + '/rpc/v5/search/aura?by=name-desc', ], r.request_uris) def testMultipleRawSearch(self): @@ -44,8 +42,8 @@ def testMultipleRawSearch(self): self.assertGreater(parsed['resultcount'], 1) self.assertCountEqual([ - '/rpc?v=5&type=search&by=name-desc&arg=aura', - '/rpc?v=5&type=search&by=name-desc&arg=systemd', + '/rpc/v5/search/aura?by=name-desc', + '/rpc/v5/search/systemd?by=name-desc', ], r.request_uris) def testRawSearchBy(self): @@ -59,7 +57,7 @@ def testRawSearchBy(self): self.assertIn('auracle-git', names) self.assertCountEqual([ - '/rpc?v=5&type=search&by=maintainer&arg=falconindy', + '/rpc/v5/search/falconindy?by=maintainer', ], r.request_uris) def testLiteralSearch(self): @@ -67,7 +65,7 @@ def testLiteralSearch(self): self.assertEqual(0, r.process.returncode) self.assertListEqual([ - '/rpc?v=5&type=search&by=name-desc&arg=%5Eaurac.%2B', + '/rpc/v5/search/^aurac.+?by=name-desc', ], r.request_uris) diff --git a/tests/test_regex_search.py b/tests/test_regex_search.py index f013660..8244b12 100644 --- a/tests/test_regex_search.py +++ b/tests/test_regex_search.py @@ -24,9 +24,9 @@ def testMultipleSearchesWithFiltering(self): self.assertEqual('auracle-git', r.process.stdout.decode().strip()) self.assertCountEqual([ - '/rpc?v=5&type=search&by=name-desc&arg=aurac', - '/rpc?v=5&type=search&by=name-desc&arg=le-git', - '/rpc?v=5&type=search&by=name-desc&arg=auracle', + '/rpc/v5/search/aurac?by=name-desc', + '/rpc/v5/search/le-git?by=name-desc', + '/rpc/v5/search/auracle?by=name-desc', ], r.request_uris) diff --git a/tests/test_search.py b/tests/test_search.py index 14a789a..339e346 100644 --- a/tests/test_search.py +++ b/tests/test_search.py @@ -48,8 +48,8 @@ def testResultsAreUnique(self): # resultcount is the same as the results are deduped. r2 = self.Auracle(['search', '--quiet', 'aura', 'aura']) self.assertCountEqual([ - '/rpc?v=5&type=search&by=name-desc&arg=aura', - '/rpc?v=5&type=search&by=name-desc&arg=aura', + '/rpc/v5/search/aura?by=name-desc', + '/rpc/v5/search/aura?by=name-desc', ], r2.request_uris) self.assertEqual(packagecount, len(r2.process.stdout.decode().splitlines())) @@ -59,7 +59,7 @@ def testLiteralSearch(self): self.assertEqual(0, r.process.returncode) self.assertListEqual([ - '/rpc?v=5&type=search&by=name-desc&arg=%5Eaurac.%2B', + '/rpc/v5/search/^aurac.+?by=name-desc', ], r.request_uris) def testLiteralSearchWithShortTerm(self): @@ -67,7 +67,7 @@ def testLiteralSearchWithShortTerm(self): self.assertEqual(1, r.process.returncode) self.assertListEqual([ - '/rpc?v=5&type=search&by=name-desc&arg=a', + '/rpc/v5/search/a?by=name-desc', ], r.request_uris) diff --git a/tests/test_show.py b/tests/test_show.py index 2f611a5..67d32e1 100644 --- a/tests/test_show.py +++ b/tests/test_show.py @@ -12,10 +12,9 @@ def testSinglePkgbuild(self): self.assertIn('pkgname=auracle-git', pkgbuild) - self.assertCountEqual([ - '/rpc?v=5&type=info&arg[]=auracle-git', - '/cgit/aur.git/plain/PKGBUILD?h=auracle-git' - ], r.request_uris) + self.assertCountEqual( + ['/rpc/v5/info', '/cgit/aur.git/plain/PKGBUILD?h=auracle-git'], + r.request_uris) def testMultiplePkgbuilds(self): r = self.Auracle(['show', 'auracle-git', 'pkgfile-git']) @@ -31,7 +30,7 @@ def testPkgbuildNotFound(self): self.assertNotEqual(0, r.process.returncode) self.assertCountEqual([ - '/rpc?v=5&type=info&arg[]=totesnotfoundpackage', + '/rpc/v5/info', ], r.request_uris) def testFileNotFound(self):