Skip to content

Commit

Permalink
feat(storage): easier mocks with BucketMetadata
Browse files Browse the repository at this point in the history
Populating all the fields for `BucketMetadata` was somewhat difficult.
The class tried to prevent applications from setting fields that only
the server would set.  I thought about adding a `BucketMetadataBuilder`,
but that would duplicate a lot of code without preventing anything. In
addition, all the other libraries use protos that allow any field to be
set, and that does not seemt to create a lot of trouble or confusion.

I also stopped using the "composition-by-private-inheritance" base
because it does not save enough code.  I expect this class will go away
once I make similar changes to `ObjectMetadata`.
  • Loading branch information
coryan committed Sep 21, 2022
1 parent 74f4ba0 commit aa7232f
Show file tree
Hide file tree
Showing 4 changed files with 269 additions and 166 deletions.
45 changes: 29 additions & 16 deletions google/cloud/storage/bucket_metadata.cc
Original file line number Diff line number Diff line change
Expand Up @@ -140,22 +140,35 @@ std::ostream& operator<<(std::ostream& os,
}

bool operator==(BucketMetadata const& lhs, BucketMetadata const& rhs) {
return static_cast<internal::CommonMetadata<BucketMetadata> const&>(lhs) ==
rhs &&
lhs.acl_ == rhs.acl_ && lhs.billing_ == rhs.billing_ &&
lhs.cors_ == rhs.cors_ &&
lhs.default_event_based_hold_ == rhs.default_event_based_hold_ &&
lhs.default_acl_ == rhs.default_acl_ &&
lhs.encryption_ == rhs.encryption_ &&
lhs.iam_configuration_ == rhs.iam_configuration_ &&
lhs.project_number_ == rhs.project_number_ &&
lhs.lifecycle_ == rhs.lifecycle_ && lhs.location_ == rhs.location_ &&
lhs.location_type_ == rhs.location_type_ &&
lhs.logging_ == rhs.logging_ && lhs.labels_ == rhs.labels_ &&
lhs.retention_policy_ == rhs.retention_policy_ &&
lhs.rpo_ == rhs.rpo_ && lhs.versioning_ == rhs.versioning_ &&
lhs.website_ == rhs.website_ &&
lhs.custom_placement_config_ == rhs.custom_placement_config_;
return lhs.acl_ == rhs.acl_ //
&& lhs.billing_ == rhs.billing_ //
&& lhs.cors_ == rhs.cors_ //
&& lhs.custom_placement_config_ == rhs.custom_placement_config_ //
&& lhs.default_acl_ == rhs.default_acl_ //
&& lhs.default_event_based_hold_ == rhs.default_event_based_hold_ //
&& lhs.encryption_ == rhs.encryption_ //
&& lhs.etag_ == rhs.etag_ //
&& lhs.iam_configuration_ == rhs.iam_configuration_ //
&& lhs.id_ == rhs.id_ //
&& lhs.kind_ == rhs.kind_ //
&& lhs.labels_ == rhs.labels_ //
&& lhs.lifecycle_ == rhs.lifecycle_ //
&& lhs.location_ == rhs.location_ //
&& lhs.location_type_ == rhs.location_type_ //
&& lhs.logging_ == rhs.logging_ //
&& lhs.metageneration_ == rhs.metageneration_ //
&& lhs.name_ == rhs.name_ //
&& lhs.owner_ == rhs.owner_ //
&& lhs.project_number_ == rhs.project_number_ //
&& lhs.retention_policy_ == rhs.retention_policy_ //
&& lhs.rpo_ == rhs.rpo_ //
&& lhs.self_link_ == rhs.self_link_ //
&& lhs.storage_class_ == rhs.storage_class_ //
&& lhs.time_created_ == rhs.time_created_ //
&& lhs.updated_ == rhs.updated_ //
&& lhs.versioning_ == rhs.versioning_ //
&& lhs.website_ == rhs.website_ //
;
}

std::ostream& operator<<(std::ostream& os, BucketMetadata const& rhs) {
Expand Down
117 changes: 96 additions & 21 deletions google/cloud/storage/bucket_metadata.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@ namespace cloud {
namespace storage {
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
namespace internal {
struct BucketMetadataParser;
struct GrpcBucketMetadataParser;
struct GrpcBucketRequestParser;
} // namespace internal

Expand Down Expand Up @@ -574,7 +572,7 @@ std::ostream& operator<<(std::ostream& os,
/**
* Represents a Google Cloud Storage Bucket Metadata object.
*/
class BucketMetadata : private internal::CommonMetadata<BucketMetadata> {
class BucketMetadata {
public:
BucketMetadata() = default;

Expand Down Expand Up @@ -710,7 +708,12 @@ class BucketMetadata : private internal::CommonMetadata<BucketMetadata> {
}
///@}

using CommonMetadata::etag;
std::string const& etag() const { return etag_; }
/// @note This is only intended for mocking.
BucketMetadata& set_etag(std::string v) {
etag_ = std::move(v);
return *this;
}

/**
* @name Get and set the IAM configuration.
Expand Down Expand Up @@ -743,8 +746,19 @@ class BucketMetadata : private internal::CommonMetadata<BucketMetadata> {
}
///@}

using CommonMetadata::id;
using CommonMetadata::kind;
std::string const& id() const { return id_; }
/// @note This is only intended for mocking
BucketMetadata& set_id(std::string v) {
id_ = std::move(v);
return *this;
}

std::string const& kind() const { return kind_; }
/// @note This is only intended for mocking
BucketMetadata& set_kind(std::string v) {
kind_ = std::move(v);
return *this;
}

/// @name Accessors and modifiers to the `labels`.
///@{
Expand Down Expand Up @@ -819,8 +833,15 @@ class BucketMetadata : private internal::CommonMetadata<BucketMetadata> {
return *this;
}

/// Returns the location type (e.g. regional vs. dual region).
std::string const& location_type() const { return location_type_; }

/// @note This is only intended for mocking.
BucketMetadata& set_location_type(std::string v) {
location_type_ = std::move(v);
return *this;
}

/// @name Accessors and modifiers for logging configuration.
///@{
bool has_logging() const { return logging_.has_value(); }
Expand All @@ -839,10 +860,15 @@ class BucketMetadata : private internal::CommonMetadata<BucketMetadata> {
///@}

/// The bucket metageneration.
using CommonMetadata::metageneration;
std::int64_t metageneration() const { return metageneration_; }
/// @note this is only intended for mocking.
BucketMetadata& set_metageneration(std::int64_t v) {
metageneration_ = v;
return *this;
}

/// The bucket name.
using CommonMetadata::name;
std::string const& name() const { return name_; }

/**
* Changes the name.
Expand All @@ -852,17 +878,46 @@ class BucketMetadata : private internal::CommonMetadata<BucketMetadata> {
* some other attribute.
*/
BucketMetadata& set_name(std::string v) {
CommonMetadata::set_name(std::move(v));
name_ = std::move(v);
return *this;
}

/// Returns true if the bucket `owner` attribute is present.
using CommonMetadata::has_owner;
using CommonMetadata::owner;
bool has_owner() const { return owner_.has_value(); }
/**
* Returns the owner.
*
* It is undefined behavior to call `owner()` if `has_owner()` is false.
*/
Owner const& owner() const { return *owner_; }

/// @note this is only intended for mocking.
BucketMetadata& set_owner(Owner v) {
owner_ = std::move(v);
return *this;
}
/// @note this is only intended for mocking.
BucketMetadata& reset_owner() {
owner_.reset();
return *this;
}

std::int64_t const& project_number() const { return project_number_; }

using CommonMetadata::self_link;
/// @note this is only intended for mocking.
BucketMetadata& set_project_number(std::int64_t v) {
project_number_ = v;
return *this;
}

/// Returns a HTTP link to retrieve the bucket metadata.
std::string const& self_link() const { return self_link_; }

/// @note this is only intended for mocking.
BucketMetadata& set_self_link(std::string v) {
self_link_ = std::move(v);
return *this;
}

/// @name Accessors and modifiers for retention policy configuration.
///@{
Expand Down Expand Up @@ -908,18 +963,31 @@ class BucketMetadata : private internal::CommonMetadata<BucketMetadata> {

/// @name Access and modify the default storage class attribute.
///@{
using CommonMetadata::storage_class;
std::string const& storage_class() const { return storage_class_; }
BucketMetadata& set_storage_class(std::string v) {
CommonMetadata::set_storage_class(std::move(v));
storage_class_ = std::move(v);
return *this;
}
///@}

/// Returns the bucket creation timestamp.
using CommonMetadata::time_created;
std::chrono::system_clock::time_point time_created() const {
return time_created_;
}
/// @note This is only intended for mocking.
BucketMetadata& set_time_created(std::chrono::system_clock::time_point v) {
time_created_ = v;
return *this;
}

/// Returns the timestamp for the last bucket metadata update.
using CommonMetadata::updated;
std::chrono::system_clock::time_point updated() const { return updated_; }

/// @note This is only intended for mocking.
BucketMetadata& set_updated(std::chrono::system_clock::time_point v) {
updated_ = v;
return *this;
}

/// @name Accessors and modifiers for versioning configuration.
///@{
Expand Down Expand Up @@ -992,29 +1060,36 @@ class BucketMetadata : private internal::CommonMetadata<BucketMetadata> {
}

private:
friend struct internal::BucketMetadataParser;
friend struct internal::GrpcBucketMetadataParser;

friend std::ostream& operator<<(std::ostream& os, BucketMetadata const& rhs);
// Keep the fields in alphabetical order.
std::vector<BucketAccessControl> acl_;
absl::optional<BucketBilling> billing_;
std::vector<CorsEntry> cors_;
bool default_event_based_hold_ = false;
absl::optional<BucketCustomPlacementConfig> custom_placement_config_;
std::vector<ObjectAccessControl> default_acl_;
bool default_event_based_hold_ = false;
absl::optional<BucketEncryption> encryption_;
std::string etag_;
absl::optional<BucketIamConfiguration> iam_configuration_;
std::string id_;
std::string kind_;
std::map<std::string, std::string> labels_;
absl::optional<BucketLifecycle> lifecycle_;
std::string location_;
std::string location_type_;
absl::optional<BucketLogging> logging_;
std::int64_t metageneration_{0};
std::string name_;
absl::optional<Owner> owner_;
std::int64_t project_number_ = 0;
absl::optional<BucketRetentionPolicy> retention_policy_;
std::string rpo_;
std::string self_link_;
std::string storage_class_;
std::chrono::system_clock::time_point time_created_;
std::chrono::system_clock::time_point updated_;
absl::optional<BucketVersioning> versioning_;
absl::optional<BucketWebsite> website_;
absl::optional<BucketCustomPlacementConfig> custom_placement_config_;
};

std::ostream& operator<<(std::ostream& os, BucketMetadata const& rhs);
Expand Down
Loading

0 comments on commit aa7232f

Please sign in to comment.