blob: 101a3ef7a30e5ddfbf65d781f7284dfc1cc624c2 [file] [log] [blame]
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <sys/socket.h>
#include <sys/un.h>
#include <gtest/gtest.h>
#include <cutils/sockets.h>
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
#include "aconfig_storage/aconfig_storage_read_api.hpp"
#include "aconfig_storage/aconfig_storage_write_api.hpp"
#include <protos/aconfig_storage_metadata.pb.h>
#include <aconfigd.pb.h>
#include "aconfigd.h"
using storage_records_pb = android::aconfig_storage_metadata::storage_files;
using storage_record_pb = android::aconfig_storage_metadata::storage_file_info;
namespace android {
namespace aconfigd {
base::Result<base::unique_fd> connect_aconfigd_socket() {
auto sock_fd = base::unique_fd(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0));
if (sock_fd == -1) {
return base::ErrnoError() << "failed create socket";
}
auto addr = sockaddr_un();
addr.sun_family = AF_UNIX;
auto path = std::string("/dev/socket/") + kAconfigdSocket;
strlcpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path));
bool success = false;
for (int retry = 0; retry < 5; retry++) {
if (connect(sock_fd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) == 0) {
success = true;
break;
}
sleep(1);
}
if (!success) {
return base::ErrnoError() << "failed to connect to aconfigd socket";
}
return sock_fd;
}
base::Result<void> send_new_storage_message() {
auto sock_fd = connect_aconfigd_socket();
if (!sock_fd.ok()) {
return Error() << sock_fd.error();
}
auto message = StorageMessage{};
auto msg = message.mutable_new_storage_message();
auto test_dir = base::GetExecutableDirectory();
msg->set_container("mockup");
msg->set_package_map(test_dir + "/tests/package.map");
msg->set_flag_map(test_dir + "/tests/flag.map");
msg->set_flag_value(test_dir + "/tests/flag.val");
auto message_string = std::string();
if (!message.SerializeToString(&message_string)) {
return Error() << "failed to serialize pb to string";
}
auto result = TEMP_FAILURE_RETRY(
send(*sock_fd, message_string.c_str(), message_string.size(), 0));
if (result != static_cast<long>(message_string.size())) {
return ErrnoError() << "send() failed";
}
char buffer[1280] = {};
auto num_bytes = TEMP_FAILURE_RETRY(recv(*sock_fd, buffer, sizeof(buffer), 0));
if (num_bytes < 0) {
return ErrnoError() << "recv() failed";
}
auto return_msg = std::string(buffer, num_bytes);
if (!return_msg.empty()) {
return Error() << "failed to add mockup storage: " << return_msg;
}
return {};
}
TEST(aconfigd_socket, new_storage_message) {
auto new_storage_result = send_new_storage_message();
ASSERT_TRUE(new_storage_result.ok()) << new_storage_result.error();
auto pb_file = "/metadata/aconfig/boot/available_storage_file_records.pb";
auto records_pb = storage_records_pb();
auto content = std::string();
ASSERT_TRUE(base::ReadFileToString(pb_file, &content)) << strerror(errno);
ASSERT_TRUE(records_pb.ParseFromString(content)) << strerror(errno);
bool found = false;
for (auto& entry : records_pb.files()) {
if (entry.container() == "mockup") {
found = true;
break;
}
}
ASSERT_TRUE(found);
}
TEST(aconfigd_socket, flag_override_message) {
auto new_storage_result = send_new_storage_message();
ASSERT_TRUE(new_storage_result.ok()) << new_storage_result.error();
auto sock_fd = connect_aconfigd_socket();
ASSERT_TRUE(sock_fd.ok()) << strerror(errno);
auto message = StorageMessage{};
auto msg = message.mutable_flag_override_message();
msg->set_package_name("com.android.aconfig.storage.test_1");
msg->set_flag_name("enabled_rw");
msg->set_flag_value("true");
auto message_string = std::string();
ASSERT_TRUE(message.SerializeToString(&message_string));
auto result = TEMP_FAILURE_RETRY(
send(*sock_fd, message_string.c_str(), message_string.size(), 0));
ASSERT_EQ(result, static_cast<long>(message_string.size())) << strerror(errno);
char buffer[1280] = {};
auto num_bytes = TEMP_FAILURE_RETRY(
recv(*sock_fd, buffer, sizeof(buffer), 0));
ASSERT_TRUE(num_bytes >= 0) << strerror(errno);
auto received_msg = std::string(buffer, num_bytes);
ASSERT_EQ(received_msg, "") << "expect empty error message returned from socket";
}
} // namespace aconfigd
} // namespace android