delete cc;
}
+class test_service_set : public service_set
+{
+ public:
+ service_record * service1 = nullptr;
+ service_record * service2 = nullptr;
+
+ virtual service_record *load_service(const char *name) override
+ {
+ auto r = find_service(name);
+ if (r == nullptr) {
+ if (strcmp(name, "test-service-1") == 0) {
+ service1 = new service_record(this, "test-service-1");
+ add_service(service1);
+ return service1;
+ }
+ else if (strcmp(name, "test-service-2") == 0) {
+ service2 = new service_record(this, "test-service-2");
+ add_service(service2);
+ return service2;
+ }
+ throw service_not_found(name);
+ }
+ return r;
+ }
+};
+
+void cptest_loadservice()
+{
+ test_service_set sset;
+
+ const char * const service_name_1 = "test-service-1";
+ const char * const service_name_2 = "test-service-2";
+
+ int fd = bp_sys::allocfd();
+ auto *cc = new control_conn_t(event_loop, &sset, fd);
+
+ std::vector<char> cmd = { DINIT_CP_LOADSERVICE };
+ uint16_t name_len = strlen(service_name_1);
+ char *name_len_cptr = reinterpret_cast<char *>(&name_len);
+ cmd.insert(cmd.end(), name_len_cptr, name_len_cptr + sizeof(name_len));
+ cmd.insert(cmd.end(), service_name_1, service_name_1 + name_len);
+
+ bp_sys::supply_read_data(fd, std::move(cmd));
+ bp_sys::set_blocking(fd);
+
+ event_loop.regd_bidi_watchers[fd]->read_ready(event_loop, fd);
+
+ // We expect:
+ // (1 byte) DINIT_RP_SERVICERECORD
+ // (1 byte) state
+ // (handle_t) handle
+ // (1 byte) target state
+
+ std::vector<char> wdata;
+ bp_sys::extract_written_data(fd, wdata);
+
+ assert(wdata.size() == 3 + sizeof(control_conn_t::handle_t));
+ assert(wdata[0] == DINIT_RP_SERVICERECORD);
+ service_state_t s = static_cast<service_state_t>(wdata[1]);
+ assert(s == service_state_t::STOPPED);
+ service_state_t ts = static_cast<service_state_t>(wdata[6]);
+ assert(ts == service_state_t::STOPPED);
+
+ assert(sset.service1 != nullptr);
+ assert(sset.service2 == nullptr);
+
+ cmd = { DINIT_CP_LOADSERVICE };
+ cmd.insert(cmd.end(), name_len_cptr, name_len_cptr + sizeof(name_len));
+ cmd.insert(cmd.end(), service_name_2, service_name_2 + name_len);
+
+ bp_sys::supply_read_data(fd, std::move(cmd));
+
+ event_loop.regd_bidi_watchers[fd]->read_ready(event_loop, fd);
+
+ // We expect:
+ // (1 byte) DINIT_RP_SERVICERECORD
+ // (1 byte) state
+ // (handle_t) handle
+ // (1 byte) target state
+
+ bp_sys::extract_written_data(fd, wdata);
+
+ assert(wdata.size() == 3 + sizeof(control_conn_t::handle_t));
+ assert(wdata[0] == DINIT_RP_SERVICERECORD);
+ s = static_cast<service_state_t>(wdata[1]);
+ assert(s == service_state_t::STOPPED);
+ ts = static_cast<service_state_t>(wdata[6]);
+ assert(ts == service_state_t::STOPPED);
+
+ assert(sset.service1 != nullptr);
+ assert(sset.service2 != nullptr);
+
+ delete cc;
+}
#define RUN_TEST(name, spacing) \
std::cout << #name "..." spacing; \
RUN_TEST(cptest_findservice1, "");
RUN_TEST(cptest_findservice2, "");
RUN_TEST(cptest_findservice3, "");
+ RUN_TEST(cptest_loadservice, " ");
return 0;
}
std::vector<char> data; // data (if errcode == 0)
};
+class read_cond : public std::vector<read_result>
+{
+ public:
+ using vector<read_result>::vector;
+
+ // if blocking, return EAGAIN rather than end-of-file:
+ bool is_blocking = false;
+};
+
// map of fd to read results to supply for reads of that fd
-std::map<int,std::vector<read_result>> read_data;
+std::map<int,read_cond> read_data;
// map of data written to each fd
std::map<int,std::vector<char>> written_data;
read_data[fd].emplace_back(std::move(data));
}
+void set_blocking(int fd)
+{
+ read_data[fd].is_blocking = true;
+}
+
// retrieve data written via write()
void extract_written_data(int fd, std::vector<char> &data)
{
ssize_t read(int fd, void *buf, size_t count)
{
- std::vector<read_result> & rrs = read_data[fd];
+ read_cond & rrs = read_data[fd];
if (rrs.empty()) {
+ if (rrs.is_blocking) {
+ errno = EAGAIN;
+ return -1;
+ }
return 0;
}