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