Skip to content

Commit 95ff4ac

Browse files
laramielcopybara-github
authored andcommitted
Improve tests for Spec::FromUrl and url_registry for | syntax.
PiperOrigin-RevId: 783835643 Change-Id: I53dcdaacb74998772702a30e1fd5b5243345c519
1 parent db8f2dd commit 95ff4ac

File tree

10 files changed

+334
-38
lines changed

10 files changed

+334
-38
lines changed

tensorstore/driver/auto/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ tensorstore_cc_test(
6565
"//tensorstore:spec",
6666
"//tensorstore:transaction",
6767
"//tensorstore/driver/zarr3",
68+
"//tensorstore/internal/os:file_util",
6869
"//tensorstore/internal/testing:json_gtest",
6970
"//tensorstore/internal/testing:scoped_directory",
7071
"//tensorstore/kvstore",

tensorstore/driver/url_registry.cc

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
#include <stddef.h>
1818

19-
#include <array>
2019
#include <optional>
2120
#include <string>
2221
#include <string_view>
@@ -92,18 +91,21 @@ Result<TransformedDriverSpec> GetTransformedDriverSpecFromUrlImpl(
9291
return absl::InvalidArgumentError("URL must be non-empty");
9392
}
9493
std::string buffer;
95-
auto end_of_scheme = url.find(':');
96-
if (end_of_scheme == std::string_view::npos) {
97-
if constexpr (!RequireColon) {
98-
end_of_scheme = url.size();
99-
buffer = tensorstore::StrCat(url, ":");
100-
url = buffer;
101-
} else {
94+
std::string_view scheme =
95+
*(absl::StrSplit(url, absl::MaxSplits(':', 1)).begin());
96+
97+
if (scheme.size() == url.size()) {
98+
if constexpr (RequireColon) {
10299
return absl::InvalidArgumentError(tensorstore::StrCat(
103100
"URL scheme must be specified in ", tensorstore::QuoteString(url)));
101+
} else {
102+
// Add a colon to the end of `url`; The compound url syntax does not
103+
// require a colon after the scheme, however registered drivers do.
104+
buffer = tensorstore::StrCat(url, ":");
105+
url = buffer;
104106
}
105107
}
106-
auto scheme = url.substr(0, end_of_scheme);
108+
107109
Handler handler;
108110
{
109111
auto& registry = GetUrlSchemeRegistry();
@@ -157,6 +159,10 @@ Result<TransformedDriverSpec> GetTransformedDriverKvStoreAdapterSpecFromUrl(
157159

158160
Result<TransformedDriverSpec> GetTransformedDriverSpecFromUrl(
159161
std::string_view url) {
162+
if (url.empty()) {
163+
return absl::InvalidArgumentError("URL must be non-empty");
164+
}
165+
160166
std::variant<std::monostate, kvstore::Spec, TransformedDriverSpec> spec;
161167

162168
auto maybe_apply_auto = [&]() -> absl::Status {
@@ -172,8 +178,8 @@ Result<TransformedDriverSpec> GetTransformedDriverSpecFromUrl(
172178
};
173179

174180
auto apply_component = [&](std::string_view component) -> absl::Status {
175-
auto scheme = static_cast<std::array<std::string_view, 1>>(
176-
absl::StrSplit(component, ':'))[0];
181+
std::string_view scheme =
182+
*(absl::StrSplit(component, absl::MaxSplits(':', 1)).begin());
177183
auto scheme_kind = internal::GetUrlSchemeKind(scheme);
178184
auto fail = [&]() -> absl::Status {
179185
if (!scheme_kind) {
@@ -247,7 +253,12 @@ Result<TransformedDriverSpec> GetTransformedDriverSpecFromUrl(
247253
};
248254

249255
for (std::string_view component : absl::StrSplit(url, '|')) {
250-
TENSORSTORE_RETURN_IF_ERROR(apply_component(component));
256+
if (auto status = apply_component(component); !status.ok()) {
257+
return tensorstore::MaybeAnnotateStatus(
258+
std::move(status),
259+
tensorstore::StrCat("Parsing spec from url: ",
260+
tensorstore::QuoteString(url)));
261+
}
251262
}
252263

253264
if (std::holds_alternative<std::monostate>(spec)) {
@@ -256,8 +267,11 @@ Result<TransformedDriverSpec> GetTransformedDriverSpecFromUrl(
256267
return absl::InvalidArgumentError("Non-empty URL must be specified");
257268
}
258269

259-
TENSORSTORE_RETURN_IF_ERROR(maybe_apply_auto());
260-
270+
if (auto status = maybe_apply_auto(); !status.ok()) {
271+
return tensorstore::MaybeAnnotateStatus(
272+
std::move(status), tensorstore::StrCat("Parsing spec from url: ",
273+
tensorstore::QuoteString(url)));
274+
}
261275
return std::move(std::get<TransformedDriverSpec>(spec));
262276
}
263277

tensorstore/kvstore/BUILD

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,3 +468,21 @@ tensorstore_cc_test(
468468
"@nlohmann_json//:json",
469469
],
470470
)
471+
472+
tensorstore_cc_test(
473+
name = "url_registry_test",
474+
srcs = ["url_registry_test.cc"],
475+
deps = [
476+
":kvstore",
477+
"//tensorstore:context",
478+
"//tensorstore/internal:intrusive_ptr",
479+
"//tensorstore/util:future",
480+
"//tensorstore/util:result",
481+
"//tensorstore/util:status_testutil",
482+
"//tensorstore/util/garbage_collection",
483+
"@abseil-cpp//absl/log:absl_log",
484+
"@abseil-cpp//absl/status",
485+
"@abseil-cpp//absl/strings",
486+
"@googletest//:gtest_main",
487+
],
488+
)

tensorstore/kvstore/kvstore_test.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ TEST(KeyValueStoreTest, TensorStoreUrl) {
6262
EXPECT_THAT(
6363
kvstore::Spec::FromJson("json:"),
6464
MatchesStatus(absl::StatusCode::kInvalidArgument,
65-
"\"json\" is a kvstore-based TensorStore URL scheme: "
65+
".*\"json\" is a kvstore-based TensorStore URL scheme: "
6666
"unsupported URL scheme \"json\" in \"json:\""));
6767
}
6868

tensorstore/kvstore/mock_kvstore.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#ifndef TENSORSTORE_KVSTORE_MOCK_KVSTORE_H_
1616
#define TENSORSTORE_KVSTORE_MOCK_KVSTORE_H_
1717

18+
#include <functional>
1819
#include <optional>
1920
#include <utility>
2021

tensorstore/kvstore/url_registry.cc

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -84,18 +84,21 @@ Result<kvstore::Spec> GetSpecFromUrlImpl(std::string_view url, Arg&&... arg) {
8484
return absl::InvalidArgumentError("URL must be non-empty");
8585
}
8686
std::string buffer;
87-
auto end_of_scheme = url.find(':');
88-
if (end_of_scheme == std::string_view::npos) {
89-
if constexpr (!RequireColon) {
90-
end_of_scheme = url.size();
91-
buffer = tensorstore::StrCat(url, ":");
92-
url = buffer;
93-
} else {
87+
std::string_view scheme =
88+
*(absl::StrSplit(url, absl::MaxSplits(':', 1)).begin());
89+
90+
if (scheme.size() == url.size()) {
91+
if constexpr (RequireColon) {
9492
return absl::InvalidArgumentError(tensorstore::StrCat(
9593
"URL scheme must be specified in ", tensorstore::QuoteString(url)));
94+
} else {
95+
// Add a colon to the end of `url`; The compound url syntax does not
96+
// require a colon after the scheme, however registered drivers do.
97+
buffer = tensorstore::StrCat(url, ":");
98+
url = buffer;
9699
}
97100
}
98-
auto scheme = url.substr(0, end_of_scheme);
101+
99102
Handler handler;
100103
{
101104
auto& registry = internal_kvstore::GetUrlSchemeRegistry();
@@ -118,10 +121,15 @@ Result<kvstore::Spec> GetSpecFromUrlImpl(std::string_view url, Arg&&... arg) {
118121
}
119122
TENSORSTORE_ASSIGN_OR_RETURN(
120123
auto spec, handler(url, std::forward<Arg>(arg)...),
121-
tensorstore::MaybeAnnotateStatus(std::move(_),
122-
tensorstore::StrCat(tensorstore::StrCat(
123-
"Invalid kvstore URL component ",
124-
tensorstore::QuoteString(url)))));
124+
tensorstore::MaybeAnnotateStatus(
125+
std::move(_), tensorstore::StrCat("Invalid kvstore URL component ",
126+
tensorstore::QuoteString(url))));
127+
if (!spec.valid()) {
128+
// This should never happen with correct kvstore drivers, but as Spec
129+
// permits invalid state, check here and error about it.
130+
return absl::InvalidArgumentError(tensorstore::StrCat(
131+
"Invalid kvstore URL component ", tensorstore::QuoteString(url)));
132+
}
125133
TENSORSTORE_RETURN_IF_ERROR(
126134
const_cast<kvstore::DriverSpec&>(*spec.driver).NormalizeSpec(spec.path));
127135
return spec;
@@ -144,18 +152,24 @@ Result<kvstore::Spec> GetAdapterSpecFromUrl(std::string_view url,
144152
namespace kvstore {
145153

146154
Result<Spec> Spec::FromUrl(std::string_view url) {
147-
auto splitter = absl::StrSplit(url, '|');
148-
auto it = splitter.begin();
149-
if (it == splitter.end()) {
150-
// Note: `absl::StrSplit` returns either zero or one component for
151-
// an empty string, depending on whether `url.data() == nullptr`.
155+
// Note: `absl::StrSplit` returns either zero or one component for
156+
// an empty string, depending on whether `url.data() == nullptr`,
157+
// so check for empty explicitly.
158+
if (url.empty()) {
152159
return absl::InvalidArgumentError("URL must be non-empty");
153160
}
154-
TENSORSTORE_ASSIGN_OR_RETURN(auto spec,
155-
internal_kvstore::GetRootSpecFromUrl(*it));
161+
auto splitter = absl::StrSplit(url, '|');
162+
auto it = splitter.begin();
163+
TENSORSTORE_ASSIGN_OR_RETURN(
164+
auto spec, internal_kvstore::GetRootSpecFromUrl(*it),
165+
tensorstore::MaybeAnnotateStatus(
166+
_, tensorstore::StrCat("Parsing spec from url: ", QuoteString(url))));
156167
while (++it != splitter.end()) {
157168
TENSORSTORE_ASSIGN_OR_RETURN(
158-
spec, internal_kvstore::GetAdapterSpecFromUrl(*it, std::move(spec)));
169+
spec, internal_kvstore::GetAdapterSpecFromUrl(*it, std::move(spec)),
170+
tensorstore::MaybeAnnotateStatus(
171+
_,
172+
tensorstore::StrCat("Parsing spec from url: ", QuoteString(url))));
159173
}
160174
return spec;
161175
}

0 commit comments

Comments
 (0)