1 // Copyright 2020 Google LLC
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 "google/cloud/storage/client.h"
16 #include "google/cloud/storage/testing/object_integration_test.h"
17 #include "google/cloud/storage/testing/storage_integration_test.h"
18 #include "google/cloud/log.h"
19 #include "google/cloud/status_or.h"
20 #include "google/cloud/testing_util/assert_ok.h"
21 #include "google/cloud/testing_util/expect_exception.h"
22 #include <gmock/gmock.h>
23 #include <sys/types.h>
24 #include <algorithm>
25 #include <cstddef>
26 #include <cstring>
27 #include <iostream>
28 #include <memory>
29 #include <string>
30
31 namespace google {
32 namespace cloud {
33 namespace storage {
34 inline namespace STORAGE_CLIENT_NS {
35 namespace {
36
37 using ObjectPlentyClientsSimultaneouslyIntegrationTest =
38 ::google::cloud::storage::testing::ObjectIntegrationTest;
39
TEST_F(ObjectPlentyClientsSimultaneouslyIntegrationTest,PlentyClientsSimultaneously)40 TEST_F(ObjectPlentyClientsSimultaneouslyIntegrationTest,
41 PlentyClientsSimultaneously) {
42 StatusOr<Client> client = MakeIntegrationTestClient();
43 ASSERT_STATUS_OK(client);
44
45 auto object_name = MakeRandomObjectName();
46
47 std::string expected = LoremIpsum();
48
49 // Create the object, but only if it does not exist already.
50 StatusOr<ObjectMetadata> meta = client->InsertObject(
51 bucket_name_, object_name, expected, IfGenerationMatch(0));
52 ASSERT_STATUS_OK(meta);
53
54 EXPECT_EQ(object_name, meta->name());
55 EXPECT_EQ(bucket_name_, meta->bucket());
56
57 // Create a iostream to read the object back.
58 auto num_fds_before_test = GetNumOpenFiles();
59 std::vector<Client> read_clients;
60 std::vector<ObjectReadStream> read_streams;
61 for (int i = 0; i != 100; ++i) {
62 auto read_client = MakeIntegrationTestClient();
63 ASSERT_STATUS_OK(read_client);
64 auto stream = read_client->ReadObject(bucket_name_, object_name);
65 char c;
66 stream.read(&c, 1);
67 read_streams.emplace_back(std::move(stream));
68 read_clients.emplace_back(*std::move(read_client));
69 }
70 auto num_fds_during_test = GetNumOpenFiles();
71 read_streams.clear();
72 read_clients.clear();
73 auto num_fds_after_test = GetNumOpenFiles();
74
75 // `GetNumOpenFiles()` is not implemented on all platforms.
76 // If they all return ok then check the values,
77 // otherwise they must all be `kUnimplemented`
78 if (num_fds_before_test.ok() && num_fds_during_test.ok() &&
79 num_fds_after_test.ok()) {
80 EXPECT_LT(*num_fds_before_test, *num_fds_during_test)
81 << "Clients keeps at least some file descriptors open";
82 EXPECT_LT(*num_fds_after_test, *num_fds_during_test)
83 << "Releasing clients also releases at least some file descriptors";
84 EXPECT_EQ(*num_fds_before_test, *num_fds_after_test)
85 << "Clients are leaking descriptors";
86 } else {
87 EXPECT_EQ(StatusCode::kUnimplemented, num_fds_before_test.status().code());
88 EXPECT_EQ(StatusCode::kUnimplemented, num_fds_during_test.status().code());
89 EXPECT_EQ(StatusCode::kUnimplemented, num_fds_after_test.status().code());
90 }
91
92 auto status = client->DeleteObject(bucket_name_, object_name);
93 ASSERT_STATUS_OK(status);
94 }
95
96 } // anonymous namespace
97 } // namespace STORAGE_CLIENT_NS
98 } // namespace storage
99 } // namespace cloud
100 } // namespace google
101