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