Skip to content

Commit 2262277

Browse files
authored
Add implementation and tests for gax::Status (googleapis#4)
* Add implementation and tests for gax::Status The gax::Status type is intended to be a cornerstone of the client library. It will be a part of the eventual StatusOr template type, and is used to determine retryability of failed operations. The type is default constructable, compares equality, defines operator<<, and provides convenience query methods for its component attributes. The underlying StatusCode is intended to closely resemble grpc::StatusCode, the semantics of which are documented in: https://grpc.io/grpc/cpp/classgrpc_1_1_status.html Includes tweaks to RetryPolicy and associated tests to remove templating and to instead concretely depend on gax::Status.
1 parent 4796072 commit 2262277

File tree

6 files changed

+433
-67
lines changed

6 files changed

+433
-67
lines changed

gax/BUILD.bazel

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,20 @@ licenses(["notice"]) # Apache 2.0
1818

1919
cc_library(
2020
name = "gax",
21-
srcs = [],
21+
srcs = [
22+
"status.cc",
23+
],
2224
hdrs = [
2325
"retry_policy.h",
26+
"status.h",
2427
],
2528
deps = [
2629
],
2730
)
2831

2932
gax_unit_tests = [
3033
"retry_policy_unittest.cc",
34+
"status_unittest.cc",
3135
]
3236

3337
[cc_test(

gax/retry_policy.h

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include <chrono>
1919
#include <memory>
2020

21+
#include "status.h"
22+
2123
namespace google {
2224
namespace gax {
2325

@@ -30,31 +32,27 @@ namespace gax {
3032
*
3133
* The application provides an instance of this class when the client is created.
3234
*/
33-
template <typename StatusType, typename RetryablePolicy>
3435
class RetryPolicy {
3536
public:
3637
virtual ~RetryPolicy() = default;
3738

3839
/**
3940
* Return a new copy of this object with the same retry criteria and fresh state.
4041
*/
41-
virtual std::unique_ptr<RetryPolicy<StatusType, RetryablePolicy>> clone() const = 0;
42+
virtual std::unique_ptr<RetryPolicy> clone() const = 0;
4243

4344
/**
4445
* Handle an RPC failure
4546
*
4647
* @return true if the RPC operation should be retried.
4748
*/
48-
virtual bool OnFailure(StatusType const& status) = 0;
49+
virtual bool OnFailure(Status const& status) = 0;
4950
};
5051

5152
/**
5253
* Implement a simple "count errors and then stop" retry policy.
5354
*/
54-
template <typename StatusType, typename RetryablePolicy>
55-
class LimitedErrorCountRetryPolicy : RetryPolicy<StatusType, RetryablePolicy> {
56-
using BaseType = RetryPolicy<StatusType, RetryablePolicy>;
57-
55+
class LimitedErrorCountRetryPolicy : RetryPolicy {
5856
public:
5957
LimitedErrorCountRetryPolicy(int max_failures)
6058
: failure_count_(0), max_failures_(max_failures) {}
@@ -65,12 +63,12 @@ class LimitedErrorCountRetryPolicy : RetryPolicy<StatusType, RetryablePolicy> {
6563
LimitedErrorCountRetryPolicy(LimitedErrorCountRetryPolicy&& rhs) noexcept
6664
: LimitedErrorCountRetryPolicy(rhs.max_failures_) {}
6765

68-
std::unique_ptr<RetryPolicy<StatusType, RetryablePolicy>> clone() const override {
69-
return std::unique_ptr<BaseType>(new LimitedErrorCountRetryPolicy<StatusType, RetryablePolicy>(*this));
66+
std::unique_ptr<RetryPolicy> clone() const override {
67+
return std::unique_ptr<RetryPolicy>(new LimitedErrorCountRetryPolicy(*this));
7068
}
7169

72-
bool OnFailure(StatusType const& status) override {
73-
return (!RetryablePolicy::IsPermanentFailure(status) &&
70+
bool OnFailure(Status const& status) override {
71+
return (!status.IsPermanentFailure() &&
7472
(failure_count_++) < max_failures_);
7573
}
7674

@@ -82,10 +80,8 @@ class LimitedErrorCountRetryPolicy : RetryPolicy<StatusType, RetryablePolicy> {
8280
/**
8381
* Implement a simple "keep trying for this time" retry policy.
8482
*/
85-
template <typename StatusType, typename RetryablePolicy, typename Clock>
86-
class LimitedDurationRetryPolicy : RetryPolicy<StatusType, RetryablePolicy> {
87-
using BaseType = RetryPolicy<StatusType, RetryablePolicy>;
88-
83+
template <typename Clock>
84+
class LimitedDurationRetryPolicy : RetryPolicy {
8985
public:
9086
template <typename duration_t>
9187
LimitedDurationRetryPolicy(duration_t max_duration) : max_duration_(max_duration),
@@ -97,12 +93,12 @@ class LimitedDurationRetryPolicy : RetryPolicy<StatusType, RetryablePolicy> {
9793
LimitedDurationRetryPolicy(LimitedDurationRetryPolicy&& rhs) noexcept
9894
: LimitedDurationRetryPolicy(rhs.max_duration_) {}
9995

100-
std::unique_ptr<RetryPolicy<StatusType, RetryablePolicy>> clone() const override {
101-
return std::unique_ptr<BaseType>(new LimitedDurationRetryPolicy<StatusType, RetryablePolicy, Clock>(*this));
96+
std::unique_ptr<RetryPolicy> clone() const override {
97+
return std::unique_ptr<RetryPolicy>(new LimitedDurationRetryPolicy<Clock>(*this));
10298
}
10399

104-
bool OnFailure(StatusType const & status) override {
105-
return (!RetryablePolicy::IsPermanentFailure(status) &&
100+
bool OnFailure(Status const & status) override {
101+
return (!status.IsPermanentFailure() &&
106102
Clock::now() < deadline_);
107103
}
108104

gax/retry_policy_unittest.cc

Lines changed: 31 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -12,33 +12,19 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
#include "googletest/include/gtest/gtest.h"
16-
#include "retry_policy.h"
1715
#include <chrono>
1816
#include <memory>
1917

18+
#include "googletest/include/gtest/gtest.h"
19+
#include "retry_policy.h"
20+
#include "status.h"
21+
2022
namespace {
2123
using namespace ::google;
2224

23-
class TestStatus {
24-
public:
25-
bool const isPermanent;
26-
};
27-
28-
class TestRetryablePolicy {
29-
public:
30-
static bool IsPermanentFailure(TestStatus const& s) {
31-
return s.isPermanent;
32-
}
33-
};
34-
35-
using RP = gax::RetryPolicy<TestStatus, TestRetryablePolicy>;
36-
37-
using LECRP = gax::LimitedErrorCountRetryPolicy<TestStatus, TestRetryablePolicy>;
38-
3925
TEST(LimitedErrorCountRetryPolicy, Basic) {
40-
LECRP tested(3);
41-
TestStatus s{false};
26+
gax::LimitedErrorCountRetryPolicy tested(3);
27+
gax::Status s;
4228
EXPECT_TRUE(tested.OnFailure(s));
4329
EXPECT_TRUE(tested.OnFailure(s));
4430
EXPECT_TRUE(tested.OnFailure(s));
@@ -47,57 +33,57 @@ TEST(LimitedErrorCountRetryPolicy, Basic) {
4733
}
4834

4935
TEST(LimitedErrorCountRetryPolicy, PermanentFailureCheck) {
50-
LECRP tested(3);
51-
TestStatus s{true};
36+
gax::LimitedErrorCountRetryPolicy tested(3);
37+
gax::Status s{gax::StatusCode::kCancelled, ""};
5238
EXPECT_FALSE(tested.OnFailure(s));
5339
}
5440

5541
TEST(LimitedErrorCountRetryPolicy, CopyConstruct) {
56-
LECRP tested(3);
57-
TestStatus s{false};
42+
gax::LimitedErrorCountRetryPolicy tested(3);
43+
gax::Status s;
5844
EXPECT_TRUE(tested.OnFailure(s));
5945
EXPECT_TRUE(tested.OnFailure(s));
6046
EXPECT_TRUE(tested.OnFailure(s));
6147
EXPECT_FALSE(tested.OnFailure(s));
6248

63-
LECRP copy(tested);
49+
gax::LimitedErrorCountRetryPolicy copy(tested);
6450
EXPECT_TRUE(copy.OnFailure(s));
6551
EXPECT_TRUE(copy.OnFailure(s));
6652
EXPECT_TRUE(copy.OnFailure(s));
6753
EXPECT_FALSE(copy.OnFailure(s));
6854
}
6955

7056
TEST(LimitedErrorCountRetryPolicy, MoveConstruct) {
71-
LECRP tested(3);
72-
TestStatus s{false};
57+
gax::LimitedErrorCountRetryPolicy tested(3);
58+
gax::Status s;
7359
EXPECT_TRUE(tested.OnFailure(s));
7460
EXPECT_TRUE(tested.OnFailure(s));
7561
EXPECT_TRUE(tested.OnFailure(s));
7662
EXPECT_FALSE(tested.OnFailure(s));
7763

78-
LECRP copy(std::move(tested));
64+
gax::LimitedErrorCountRetryPolicy copy(std::move(tested));
7965
EXPECT_TRUE(copy.OnFailure(s));
8066
EXPECT_TRUE(copy.OnFailure(s));
8167
EXPECT_TRUE(copy.OnFailure(s));
8268
EXPECT_FALSE(copy.OnFailure(s));
8369
}
8470

8571
TEST(LimitedErrorCountRetryPolicy, Clone) {
86-
LECRP tested(3);
87-
TestStatus s{false};
72+
gax::LimitedErrorCountRetryPolicy tested(3);
73+
gax::Status s;
8874
EXPECT_TRUE(tested.OnFailure(s));
8975
EXPECT_TRUE(tested.OnFailure(s));
9076
EXPECT_TRUE(tested.OnFailure(s));
9177
EXPECT_FALSE(tested.OnFailure(s));
9278

93-
std::unique_ptr<RP> clone = tested.clone();
79+
std::unique_ptr<gax::RetryPolicy> clone = tested.clone();
9480
EXPECT_TRUE(clone->OnFailure(s));
9581
EXPECT_TRUE(clone->OnFailure(s));
9682
EXPECT_TRUE(clone->OnFailure(s));
9783
EXPECT_FALSE(clone->OnFailure(s));
9884
}
9985

100-
static std::chrono::time_point<std::chrono::system_clock> now_point = std::chrono::system_clock::now();
86+
static std::chrono::time_point<std::chrono::system_clock> now_point;
10187

10288
class TestClock {
10389
public:
@@ -106,11 +92,9 @@ class TestClock {
10692
}
10793
};
10894

109-
using LDRP = gax::LimitedDurationRetryPolicy<TestStatus, TestRetryablePolicy, TestClock>;
110-
11195
TEST(LimitedDurationRetryPolicy, Basic) {
112-
LDRP tested(std::chrono::milliseconds(5));
113-
TestStatus s{false};
96+
gax::LimitedDurationRetryPolicy<TestClock> tested(std::chrono::milliseconds(5));
97+
gax::Status s;
11498
EXPECT_TRUE(tested.OnFailure(s));
11599

116100
now_point += std::chrono::milliseconds(2);
@@ -121,42 +105,42 @@ TEST(LimitedDurationRetryPolicy, Basic) {
121105
}
122106

123107
TEST(LimitedDurationRetryPolicy, PermanentFailureCheck) {
124-
LDRP tested(std::chrono::milliseconds(5));
125-
TestStatus s{true};
108+
gax::LimitedDurationRetryPolicy<TestClock> tested(std::chrono::milliseconds(5));
109+
gax::Status s{gax::StatusCode::kCancelled, ""};
126110

127111
EXPECT_FALSE(tested.OnFailure(s));
128112
}
129113

130114
TEST(LimitedDurationRetryPolicy, CopyConstruct) {
131-
LDRP tested(std::chrono::milliseconds(5));
132-
TestStatus s{false};
115+
gax::LimitedDurationRetryPolicy<TestClock> tested(std::chrono::milliseconds(5));
116+
gax::Status s;
133117

134118
now_point += std::chrono::milliseconds(10);
135119
EXPECT_FALSE(tested.OnFailure(s));
136120

137-
LDRP copy(tested);
121+
gax::LimitedDurationRetryPolicy<TestClock> copy(tested);
138122
EXPECT_TRUE(copy.OnFailure(s));
139123
}
140124

141125
TEST(LimitedDurationRetryPolicy, MoveConstruct) {
142-
LDRP tested(std::chrono::milliseconds(5));
143-
TestStatus s{false};
126+
gax::LimitedDurationRetryPolicy<TestClock> tested(std::chrono::milliseconds(5));
127+
gax::Status s;
144128

145129
now_point += std::chrono::milliseconds(10);
146130
EXPECT_FALSE(tested.OnFailure(s));
147131

148-
LDRP copy(std::move(tested));
132+
gax::LimitedDurationRetryPolicy<TestClock> copy(std::move(tested));
149133
EXPECT_TRUE(copy.OnFailure(s));
150134
}
151135

152136
TEST(LimitedDurationRetryPolicy, Clone) {
153-
LDRP tested(std::chrono::milliseconds(5));
154-
TestStatus s{false};
137+
gax::LimitedDurationRetryPolicy<TestClock> tested(std::chrono::milliseconds(5));
138+
gax::Status s;
155139

156140
now_point += std::chrono::milliseconds(10);
157141
EXPECT_FALSE(tested.OnFailure(s));
158142

159-
std::unique_ptr<RP> clone = tested.clone();
143+
std::unique_ptr<gax::RetryPolicy> clone = tested.clone();
160144
EXPECT_TRUE(clone->OnFailure(s));
161145
}
162146

gax/status.cc

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright 2019 Google Inc. All rights reserved
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include <ostream>
16+
#include <string>
17+
18+
#include "status.h"
19+
20+
namespace google {
21+
namespace gax {
22+
23+
std::string StatusCodeToString(StatusCode code) {
24+
switch (code) {
25+
case StatusCode::kOk:
26+
return "OK";
27+
case StatusCode::kCancelled:
28+
return "CANCELLED";
29+
case StatusCode::kUnknown:
30+
return "UNKNOWN";
31+
case StatusCode::kInvalidArgument:
32+
return "INVALID_ARGUMENT";
33+
case StatusCode::kDeadlineExceeded:
34+
return "DEADLINE_EXCEEDED";
35+
case StatusCode::kNotFound:
36+
return "NOT_FOUND";
37+
case StatusCode::kAlreadyExists:
38+
return "ALREADY_EXISTS";
39+
case StatusCode::kPermissionDenied:
40+
return "PERMISSION_DENIED";
41+
case StatusCode::kResourceExhausted:
42+
return "RESOURCE_EXHAUSTED";
43+
case StatusCode::kFailedPrecondition:
44+
return "FAILED_PRECONDITION";
45+
case StatusCode::kAborted:
46+
return "ABORTED";
47+
case StatusCode::kOutOfRange:
48+
return "OUT_OF_RANGE";
49+
case StatusCode::kUnimplemented:
50+
return "UNIMPLEMENTED";
51+
case StatusCode::kInternal:
52+
return "INTERNAL";
53+
case StatusCode::kUnavailable:
54+
return "UNAVAILABLE";
55+
case StatusCode::kDataLoss:
56+
return "DATA_LOSS";
57+
case StatusCode::kUnauthenticated:
58+
return "UNAUTHENTICATED";
59+
default:
60+
return "UNEXPECTED_STATUS_CODE=" + std::to_string(static_cast<int>(code));
61+
}
62+
}
63+
64+
std::ostream& operator<<(std::ostream& os, StatusCode code){
65+
return os << StatusCodeToString(code);
66+
}
67+
68+
std::ostream& operator<<(std::ostream& os, Status const& rhs) {
69+
return os << rhs.message() << " [" << rhs.code() << "]";
70+
}
71+
72+
} // namespace gax
73+
} // namespace google

0 commit comments

Comments
 (0)