1 // Copyright 2018 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/notification_metadata.h"
16 #include "google/cloud/storage/internal/notification_requests.h"
17 #include "google/cloud/storage/notification_event_type.h"
18 #include "google/cloud/storage/notification_payload_format.h"
19 #include <gmock/gmock.h>
20 
21 namespace google {
22 namespace cloud {
23 namespace storage {
24 inline namespace STORAGE_CLIENT_NS {
25 namespace {
26 
27 using ::testing::HasSubstr;
28 
CreateNotificationMetadataForTest()29 NotificationMetadata CreateNotificationMetadataForTest() {
30   std::string text = R"""({
31       "custom_attributes": {
32           "test-ca-1": "value1",
33           "test-ca-2": "value2"
34       },
35       "etag": "XYZ=",
36       "event_types": [
37           "OBJECT_FINALIZE",
38           "OBJECT_METADATA_UPDATE",
39           "OBJECT_DELETE",
40           "OBJECT_ARCHIVE"
41       ],
42       "id": "test-id-123",
43       "kind": "storage#notification",
44       "object_name_prefix": "test-prefix-",
45       "payload_format": "JSON_API_V1",
46       "selfLink": "https://storage.googleapis.com/storage/v1/b/test-bucket/notificationConfigs/test-id-123",
47       "topic": "test-topic"
48 })""";
49   return internal::NotificationMetadataParser::FromString(text).value();
50 }
51 
52 /// @test Verifies NotificationMetadata iostream operator.
TEST(NotificationMetadataTest,IOStream)53 TEST(NotificationMetadataTest, IOStream) {
54   auto notification = CreateNotificationMetadataForTest();
55   std::ostringstream os;
56   os << notification;
57   auto actual = os.str();
58   EXPECT_THAT(actual, HasSubstr("test-ca-1"));
59   EXPECT_THAT(actual, HasSubstr("value1"));
60   EXPECT_THAT(actual, HasSubstr("test-ca-2"));
61   EXPECT_THAT(actual, HasSubstr("value2"));
62   EXPECT_THAT(actual, HasSubstr("XYZ="));
63   EXPECT_THAT(actual, HasSubstr(event_type::ObjectFinalize()));
64   EXPECT_THAT(actual, HasSubstr(event_type::ObjectMetadataUpdate()));
65   EXPECT_THAT(actual, HasSubstr(event_type::ObjectDelete()));
66   EXPECT_THAT(actual, HasSubstr(event_type::ObjectArchive()));
67   EXPECT_THAT(actual, HasSubstr("test-id-123"));
68   EXPECT_THAT(actual, HasSubstr("storage#notification"));
69   EXPECT_THAT(actual, HasSubstr(payload_format::JsonApiV1()));
70   EXPECT_THAT(actual, HasSubstr("https://storage.googleapis.com/"));
71   EXPECT_THAT(actual, HasSubstr("test-topic"));
72 }
73 
74 /// @test Verifies NotificationMetadata::JsonPayloadForInsert.
TEST(NotificationMetadataTest,JsonPayloadForInsert)75 TEST(NotificationMetadataTest, JsonPayloadForInsert) {
76   auto notification = CreateNotificationMetadataForTest();
77   auto text = notification.JsonPayloadForInsert();
78   auto actual = nlohmann::json::parse(text);
79 
80   nlohmann::json expected_attributes{
81       {"test-ca-1", "value1"},
82       {"test-ca-2", "value2"},
83   };
84   std::vector<std::string> expected_event_types{
85       "OBJECT_FINALIZE",
86       "OBJECT_METADATA_UPDATE",
87       "OBJECT_DELETE",
88       "OBJECT_ARCHIVE",
89   };
90   nlohmann::json expected{
91       {"custom_attributes", expected_attributes},
92       {"topic", "test-topic"},
93       {"payload_format", "JSON_API_V1"},
94       {"event_types", expected_event_types},
95       {"object_name_prefix", "test-prefix-"},
96   };
97 
98   auto diff = nlohmann::json::diff(expected, actual);
99   EXPECT_EQ("[]", diff.dump()) << " text=" << text;
100 }
101 
102 /// @test Verify we can make changes to the custom attributes.
TEST(NotificationMetadataTest,MutableCustomAttributes)103 TEST(NotificationMetadataTest, MutableCustomAttributes) {
104   auto expected = CreateNotificationMetadataForTest();
105   auto copy = expected;
106   EXPECT_EQ(expected, copy);
107   copy.mutable_custom_attributes().emplace("test-ca-3", "value3");
108   EXPECT_TRUE(copy.has_custom_attribute("test-ca-3"));
109   EXPECT_EQ("value3", copy.custom_attribute("test-ca-3"));
110   EXPECT_NE(expected, copy);
111 }
112 
113 /// @test Verify we can delete custom attributes.
TEST(NotificationMetadataTest,DeleteCustomAttribute)114 TEST(NotificationMetadataTest, DeleteCustomAttribute) {
115   auto expected = CreateNotificationMetadataForTest();
116   auto copy = expected;
117   EXPECT_EQ(expected, copy);
118   copy.delete_custom_attribute("test-ca-1");
119   EXPECT_FALSE(copy.has_custom_attribute("test-ca-1"));
120   EXPECT_NE(expected, copy);
121 }
122 
123 /// @test Verify we can update and insert custom attributes.
TEST(NotificationMetadataTest,UpsertCustomAttribute)124 TEST(NotificationMetadataTest, UpsertCustomAttribute) {
125   auto expected = CreateNotificationMetadataForTest();
126   auto copy = expected;
127   EXPECT_EQ(expected, copy);
128   EXPECT_TRUE(copy.has_custom_attribute("test-ca-1"));
129   EXPECT_EQ("value1", copy.custom_attribute("test-ca-1"));
130   copy.upsert_custom_attributes("test-ca-3", "value3");
131   copy.upsert_custom_attributes("test-ca-1", "value1-updated");
132   EXPECT_EQ("value1-updated", copy.custom_attribute("test-ca-1"));
133   EXPECT_EQ("value3", copy.custom_attribute("test-ca-3"));
134   EXPECT_NE(expected, copy);
135 }
136 
137 /// @test Verify we can make changes to the event types.
TEST(NotificationMetadataTest,MutableEventTypes)138 TEST(NotificationMetadataTest, MutableEventTypes) {
139   auto expected = CreateNotificationMetadataForTest();
140   auto copy = expected;
141   EXPECT_EQ(expected, copy);
142   copy.mutable_event_types().pop_back();
143   EXPECT_EQ(3, copy.event_type_size());
144   EXPECT_NE(expected, copy);
145 }
146 
147 /// @test Verify we can make changes to the event types.
TEST(NotificationMetadataTest,AppendEventTypes)148 TEST(NotificationMetadataTest, AppendEventTypes) {
149   auto expected = CreateNotificationMetadataForTest();
150   auto copy = expected;
151   EXPECT_EQ(expected, copy);
152   copy.mutable_event_types().clear();
153   EXPECT_EQ(0, copy.event_type_size());
154   copy.append_event_type(event_type::ObjectFinalize());
155   EXPECT_EQ(1, copy.event_type_size());
156   EXPECT_EQ("OBJECT_FINALIZE", copy.event_type(0));
157   EXPECT_NE(expected, copy);
158 }
159 
160 /// @test Verify we can make changes to the object name prefix.
TEST(NotificationMetadataTest,SetObjectNamePrefix)161 TEST(NotificationMetadataTest, SetObjectNamePrefix) {
162   auto expected = CreateNotificationMetadataForTest();
163   auto copy = expected;
164   EXPECT_EQ(expected, copy);
165   EXPECT_EQ("test-prefix-", copy.object_name_prefix());
166   copy.set_object_name_prefix("another-prefix/");
167   EXPECT_EQ("another-prefix/", copy.object_name_prefix());
168   EXPECT_NE(expected, copy);
169 }
170 
171 /// @test Verify we can make changes to the payload format.
TEST(NotificationMetadataTest,SetPayloadFormat)172 TEST(NotificationMetadataTest, SetPayloadFormat) {
173   auto expected = CreateNotificationMetadataForTest();
174   auto copy = expected;
175   EXPECT_EQ(expected, copy);
176   EXPECT_EQ("JSON_API_V1", copy.payload_format());
177   copy.set_payload_format(payload_format::None());
178   EXPECT_EQ("NONE", copy.payload_format());
179   EXPECT_NE(expected, copy);
180 }
181 
182 /// @test Verify we can make changes to the topic.
TEST(NotificationMetadataTest,SetTopic)183 TEST(NotificationMetadataTest, SetTopic) {
184   auto expected = CreateNotificationMetadataForTest();
185   auto copy = expected;
186   EXPECT_EQ(expected, copy);
187   EXPECT_EQ("test-topic", copy.topic());
188   copy.set_topic("another-topic");
189   EXPECT_EQ("another-topic", copy.topic());
190   EXPECT_NE(expected, copy);
191 }
192 
193 }  // namespace
194 }  // namespace STORAGE_CLIENT_NS
195 }  // namespace storage
196 }  // namespace cloud
197 }  // namespace google
198