Skip to content
This repository was archived by the owner on Dec 8, 2021. It is now read-only.

Commit 8d97487

Browse files
authored
feat: add more DataType tests (#1097)
Part of #1096 This PR adds DataType integration tests for all the non-aggregate spanner value types that. I'll add the array and struct types in a follow up PR.
1 parent 0945dec commit 8d97487

2 files changed

Lines changed: 158 additions & 32 deletions

File tree

google/cloud/spanner/integration_tests/data_types_integration_test.cc

Lines changed: 153 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "google/cloud/spanner/client.h"
1616
#include "google/cloud/spanner/database.h"
1717
#include "google/cloud/spanner/database_admin_client.h"
18+
#include "google/cloud/spanner/internal/time.h"
1819
#include "google/cloud/spanner/mutations.h"
1920
#include "google/cloud/spanner/testing/database_environment.h"
2021
#include "google/cloud/internal/getenv.h"
@@ -28,6 +29,36 @@ namespace spanner {
2829
inline namespace SPANNER_CLIENT_NS {
2930
namespace {
3031

32+
using ::testing::UnorderedElementsAreArray;
33+
34+
// A helper function used in the test fixtures below. This function writes the
35+
// given data to the DataTypes table, then it reads all the data back and
36+
// returns it to the caller.
37+
template <typename T>
38+
StatusOr<T> WriteReadData(Client& client, T const& data,
39+
std::string const& column) {
40+
auto commit_result = client.Commit(
41+
[&data, &column](Transaction const&) -> StatusOr<Mutations> {
42+
Mutations mutations;
43+
int id = 0;
44+
for (auto const& x : data) {
45+
mutations.push_back(MakeInsertMutation(
46+
"DataTypes", {"Id", column}, "Id-" + std::to_string(id++), x));
47+
}
48+
return mutations;
49+
});
50+
if (!commit_result) return commit_result.status();
51+
52+
T actual;
53+
auto rows = client.Read("DataTypes", KeySet::All(), {column});
54+
using RowType = std::tuple<typename T::value_type>;
55+
for (auto const& row : StreamOf<RowType>(rows)) {
56+
if (!row) return row.status();
57+
actual.push_back(std::get<0>(*row));
58+
}
59+
return actual;
60+
}
61+
3162
class DataTypeIntegrationTest : public ::testing::Test {
3263
public:
3364
static void SetUpTestSuite() {
@@ -38,7 +69,6 @@ class DataTypeIntegrationTest : public ::testing::Test {
3869
void SetUp() override {
3970
auto commit_result = client_->Commit([](Transaction const&) {
4071
return Mutations{
41-
MakeDeleteMutation("Singers", KeySet::All()),
4272
MakeDeleteMutation("DataTypes", KeySet::All()),
4373
};
4474
});
@@ -53,37 +83,129 @@ class DataTypeIntegrationTest : public ::testing::Test {
5383

5484
std::unique_ptr<Client> DataTypeIntegrationTest::client_;
5585

56-
TEST_F(DataTypeIntegrationTest, ReadWriteDate) {
57-
auto& client = *client_;
58-
using RowType = std::tuple<std::string, Date, std::string>;
59-
RowType read_back;
60-
auto commit_result = client_->Commit(
61-
[&client, &read_back](Transaction const& txn) -> StatusOr<Mutations> {
62-
auto result = client.ExecuteDml(
63-
txn,
64-
SqlStatement(
65-
"INSERT INTO DataTypes (Id, DateValue, StringValue) "
66-
"VALUES(@id, @date, @event)",
67-
{{"id", Value("ReadWriteDate-1")},
68-
{"date", Value(Date(161, 3, 8))},
69-
{"event", Value("Marcus Aurelius ascends to the throne")}}));
70-
if (!result) return std::move(result).status();
71-
72-
auto reader = client.ExecuteQuery(
73-
txn, SqlStatement("SELECT Id, DateValue, StringValue FROM DataTypes"
74-
" WHERE Id = @id",
75-
{{"id", Value("ReadWriteDate-1")}}));
76-
77-
auto row = GetSingularRow(StreamOf<RowType>(reader));
78-
if (!row) return std::move(row).status();
79-
read_back = *std::move(row);
80-
return Mutations{};
81-
});
86+
TEST_F(DataTypeIntegrationTest, WriteReadBool) {
87+
std::vector<bool> const data = {true, false};
88+
auto result = WriteReadData(*client_, data, "BoolValue");
89+
ASSERT_STATUS_OK(result);
90+
EXPECT_THAT(*result, UnorderedElementsAreArray(data));
91+
}
92+
93+
TEST_F(DataTypeIntegrationTest, WriteReadInt64) {
94+
std::vector<std::int64_t> const data = {
95+
std::numeric_limits<std::int64_t>::min(), -123, -42, -1, 0, 1, 42, 123,
96+
std::numeric_limits<std::int64_t>::max(),
97+
};
98+
auto result = WriteReadData(*client_, data, "Int64Value");
99+
ASSERT_STATUS_OK(result);
100+
EXPECT_THAT(*result, UnorderedElementsAreArray(data));
101+
}
102+
103+
TEST_F(DataTypeIntegrationTest, WriteReadFloat64) {
104+
std::vector<double> const data = {
105+
-std::numeric_limits<double>::infinity(),
106+
std::numeric_limits<double>::lowest(),
107+
std::numeric_limits<double>::min(),
108+
-123.456,
109+
-123,
110+
-42.42,
111+
-42,
112+
-1.5,
113+
-1,
114+
-0.5,
115+
0,
116+
0.5,
117+
1,
118+
1.5,
119+
42,
120+
42.42,
121+
123,
122+
123.456,
123+
std::numeric_limits<double>::max(),
124+
std::numeric_limits<double>::infinity(),
125+
};
126+
auto result = WriteReadData(*client_, data, "Float64Value");
127+
ASSERT_STATUS_OK(result);
128+
EXPECT_THAT(*result, UnorderedElementsAreArray(data));
129+
}
130+
131+
TEST_F(DataTypeIntegrationTest, WriteReadFloat64NaN) {
132+
// Since NaN is not equal to anything, including itself, we need to handle
133+
// NaN separately from other Float64 values.
134+
std::vector<double> const data = {
135+
std::numeric_limits<double>::quiet_NaN(),
136+
};
137+
auto result = WriteReadData(*client_, data, "Float64Value");
138+
ASSERT_STATUS_OK(result);
139+
EXPECT_EQ(1, result->size());
140+
EXPECT_TRUE(std::isnan(result->front()));
141+
}
142+
143+
TEST_F(DataTypeIntegrationTest, WriteReadString) {
144+
std::vector<std::string> const data = {
145+
"",
146+
"a",
147+
"Hello World",
148+
"123456789012345678901234567890",
149+
std::string(1024, 'x'),
150+
};
151+
auto result = WriteReadData(*client_, data, "StringValue");
152+
ASSERT_STATUS_OK(result);
153+
EXPECT_THAT(*result, UnorderedElementsAreArray(data));
154+
}
155+
156+
TEST_F(DataTypeIntegrationTest, WriteReadBytes) {
157+
// Makes a blob containing unprintable characters.
158+
std::string blob;
159+
for (char c = std::numeric_limits<char>::min();
160+
c != std::numeric_limits<char>::max(); ++c) {
161+
blob.push_back(c);
162+
}
163+
std::vector<Bytes> const data = {
164+
Bytes(""),
165+
Bytes("a"),
166+
Bytes("Hello World"),
167+
Bytes("123456789012345678901234567890"),
168+
Bytes(blob),
169+
};
170+
auto result = WriteReadData(*client_, data, "BytesValue");
171+
ASSERT_STATUS_OK(result);
172+
EXPECT_THAT(*result, UnorderedElementsAreArray(data));
173+
}
174+
175+
TEST_F(DataTypeIntegrationTest, WriteReadTimestamp) {
176+
// TODO(#1098): `Timestamp` cannot represent these extreme values.
177+
// auto min = internal::TimestampFromString("0001-01-01T00:00:00Z");
178+
// auto max = internal::TimestampFromString("9999-12-31T23:59:59.999999999Z");
179+
180+
// ASSERT_STATUS_OK(min);
181+
// ASSERT_STATUS_OK(max);
182+
183+
std::vector<Timestamp> const data = {
184+
// *min, // TODO(#1098)
185+
Timestamp(std::chrono::seconds(-1)),
186+
Timestamp(std::chrono::nanoseconds(-1)),
187+
Timestamp(std::chrono::seconds(0)),
188+
Timestamp(std::chrono::nanoseconds(1)),
189+
Timestamp(std::chrono::seconds(1)),
190+
Timestamp(std::chrono::system_clock::now()),
191+
// *max, // TODO(#1098)
192+
};
193+
auto result = WriteReadData(*client_, data, "TimestampValue");
194+
ASSERT_STATUS_OK(result);
195+
EXPECT_THAT(*result, UnorderedElementsAreArray(data));
196+
}
82197

83-
ASSERT_TRUE(commit_result.ok());
84-
EXPECT_EQ("ReadWriteDate-1", std::get<0>(read_back));
85-
EXPECT_EQ(Date(161, 3, 8), std::get<1>(read_back));
86-
EXPECT_EQ("Marcus Aurelius ascends to the throne", std::get<2>(read_back));
198+
TEST_F(DataTypeIntegrationTest, WriteReadDate) {
199+
std::vector<Date> const data = {
200+
Date(1, 1, 1), //
201+
Date(161, 3, 8), //
202+
Date(), //
203+
Date(2019, 11, 21), //
204+
Date(9999, 12, 31), //
205+
};
206+
auto result = WriteReadData(*client_, data, "DateValue");
207+
ASSERT_STATUS_OK(result);
208+
EXPECT_THAT(*result, UnorderedElementsAreArray(data));
87209
}
88210

89211
} // namespace

google/cloud/spanner/testing/database_environment.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,12 @@ void DatabaseEnvironment::SetUp() {
5252
R"sql(CREATE TABLE DataTypes (
5353
Id STRING(256) NOT NULL,
5454
BoolValue BOOL,
55-
DateValue DATE,
55+
Int64Value INT64,
56+
Float64Value FLOAT64,
5657
StringValue STRING(1024),
58+
BytesValue BYTES(1024),
59+
TimestampValue TIMESTAMP,
60+
DateValue DATE
5761
) PRIMARY KEY (Id))sql"});
5862
int i = 0;
5963
int const timeout = 120;

0 commit comments

Comments
 (0)