Document graph service usage with docs and unit tests.
PiperOrigin-RevId: 513955877
This commit is contained in:
parent
3854d9fcd5
commit
9c3abcd06f
|
@ -1533,6 +1533,7 @@ cc_test(
|
||||||
"//mediapipe/framework/port:parse_text_proto",
|
"//mediapipe/framework/port:parse_text_proto",
|
||||||
"//mediapipe/framework/port:ret_check",
|
"//mediapipe/framework/port:ret_check",
|
||||||
"//mediapipe/framework/port:status",
|
"//mediapipe/framework/port:status",
|
||||||
|
"//mediapipe/framework/port:status_matchers",
|
||||||
"//mediapipe/framework/tool:sink",
|
"//mediapipe/framework/tool:sink",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -141,6 +141,12 @@ class CalculatorContract {
|
||||||
class GraphServiceRequest {
|
class GraphServiceRequest {
|
||||||
public:
|
public:
|
||||||
// APIs that should be used by calculators.
|
// APIs that should be used by calculators.
|
||||||
|
//
|
||||||
|
// Indicates that requested service is optional and calculator can operate
|
||||||
|
// correctly without it.
|
||||||
|
//
|
||||||
|
// NOTE: `CalculatorGraph` will still try to create services which allow
|
||||||
|
// default initialization. (See `CalculatorGraph::UseService`)
|
||||||
GraphServiceRequest& Optional() {
|
GraphServiceRequest& Optional() {
|
||||||
optional_ = true;
|
optional_ = true;
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -158,6 +164,17 @@ class CalculatorContract {
|
||||||
bool optional_ = false;
|
bool optional_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Indicates specific `service` is required for graph execution.
|
||||||
|
//
|
||||||
|
// For services which allow default initialization:
|
||||||
|
// - `CalculatorGraph` will try to create corresponding service object by
|
||||||
|
// default even if request is made optional
|
||||||
|
// (`GraphServiceRequest::Optional()`)
|
||||||
|
//
|
||||||
|
// For services which disallow default initialization:
|
||||||
|
// - `CalculatorGraph` requires client to set corresponding service object and
|
||||||
|
// otherwise fails, unles request is mad optional
|
||||||
|
// (`GraphServiceRequest::Optional()`)
|
||||||
GraphServiceRequest& UseService(const GraphServiceBase& service) {
|
GraphServiceRequest& UseService(const GraphServiceBase& service) {
|
||||||
auto it = service_requests_.emplace(service.key, service).first;
|
auto it = service_requests_.emplace(service.key, service).first;
|
||||||
return it->second;
|
return it->second;
|
||||||
|
|
|
@ -157,5 +157,191 @@ TEST_F(GraphServiceTest, CreateDefault) {
|
||||||
MP_EXPECT_OK(kNeedsCreateService.CreateDefaultObject());
|
MP_EXPECT_OK(kNeedsCreateService.CreateDefaultObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TestServiceData {};
|
||||||
|
|
||||||
|
const GraphService<TestServiceData> kTestServiceAllowDefaultInitialization(
|
||||||
|
"kTestServiceAllowDefaultInitialization",
|
||||||
|
GraphServiceBase::kAllowDefaultInitialization);
|
||||||
|
|
||||||
|
// This is only for test purposes. Ideally, a calculator that fails when service
|
||||||
|
// is not available, should request the service as non-Optional.
|
||||||
|
class FailOnUnavailableOptionalServiceCalculator : public CalculatorBase {
|
||||||
|
public:
|
||||||
|
static absl::Status GetContract(CalculatorContract* cc) {
|
||||||
|
cc->UseService(kTestServiceAllowDefaultInitialization).Optional();
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
absl::Status Open(CalculatorContext* cc) final {
|
||||||
|
RET_CHECK(cc->Service(kTestServiceAllowDefaultInitialization).IsAvailable())
|
||||||
|
<< "Service is unavailable.";
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
absl::Status Process(CalculatorContext* cc) final { return absl::OkStatus(); }
|
||||||
|
};
|
||||||
|
REGISTER_CALCULATOR(FailOnUnavailableOptionalServiceCalculator);
|
||||||
|
|
||||||
|
// Documents and ensures current behavior for requesting optional
|
||||||
|
// "AllowDefaultInitialization" services:
|
||||||
|
// - Service object is created by default.
|
||||||
|
TEST(AllowDefaultInitializationGraphServiceTest,
|
||||||
|
ServiceIsAvailableWithOptionalUse) {
|
||||||
|
CalculatorGraphConfig config =
|
||||||
|
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"pb(
|
||||||
|
node { calculator: 'FailOnUnavailableOptionalServiceCalculator' }
|
||||||
|
)pb");
|
||||||
|
|
||||||
|
CalculatorGraph graph;
|
||||||
|
MP_ASSERT_OK(graph.Initialize(config));
|
||||||
|
MP_ASSERT_OK(graph.StartRun({}));
|
||||||
|
MP_EXPECT_OK(graph.WaitUntilIdle());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Documents and ensures current behavior for setting `nullptr` service objects
|
||||||
|
// for "AllowDefaultInitialization" optional services.
|
||||||
|
// - It's allowed.
|
||||||
|
// - It disables creation of "AllowDefaultInitialization" service objects, hence
|
||||||
|
// results in optional service unavailability.
|
||||||
|
TEST(AllowDefaultInitializationGraphServiceTest,
|
||||||
|
NullServiceObjectIsAllowAndResultsInOptionalServiceUnavailability) {
|
||||||
|
CalculatorGraphConfig config =
|
||||||
|
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"pb(
|
||||||
|
node { calculator: 'FailOnUnavailableOptionalServiceCalculator' }
|
||||||
|
)pb");
|
||||||
|
|
||||||
|
CalculatorGraph graph;
|
||||||
|
std::shared_ptr<TestServiceData> object = nullptr;
|
||||||
|
MP_ASSERT_OK(
|
||||||
|
graph.SetServiceObject(kTestServiceAllowDefaultInitialization, object));
|
||||||
|
MP_ASSERT_OK(graph.Initialize(config));
|
||||||
|
MP_ASSERT_OK(graph.StartRun({}));
|
||||||
|
EXPECT_THAT(graph.WaitUntilIdle(),
|
||||||
|
StatusIs(absl::StatusCode::kInternal,
|
||||||
|
HasSubstr("Service is unavailable.")));
|
||||||
|
}
|
||||||
|
|
||||||
|
class FailOnUnavailableServiceCalculator : public CalculatorBase {
|
||||||
|
public:
|
||||||
|
static absl::Status GetContract(CalculatorContract* cc) {
|
||||||
|
cc->UseService(kTestServiceAllowDefaultInitialization);
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
absl::Status Open(CalculatorContext* cc) final {
|
||||||
|
RET_CHECK(cc->Service(kTestServiceAllowDefaultInitialization).IsAvailable())
|
||||||
|
<< "Service is unavailable.";
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
absl::Status Process(CalculatorContext* cc) final { return absl::OkStatus(); }
|
||||||
|
};
|
||||||
|
REGISTER_CALCULATOR(FailOnUnavailableServiceCalculator);
|
||||||
|
|
||||||
|
// Documents and ensures current behavior for requesting optional
|
||||||
|
// "AllowDefaultInitialization" services:
|
||||||
|
// - Service object is created by default.
|
||||||
|
TEST(AllowDefaultInitializationGraphServiceTest, ServiceIsAvailable) {
|
||||||
|
CalculatorGraphConfig config =
|
||||||
|
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"pb(
|
||||||
|
node { calculator: 'FailOnUnavailableServiceCalculator' }
|
||||||
|
)pb");
|
||||||
|
|
||||||
|
CalculatorGraph graph;
|
||||||
|
MP_ASSERT_OK(graph.Initialize(config));
|
||||||
|
MP_ASSERT_OK(graph.StartRun({}));
|
||||||
|
MP_EXPECT_OK(graph.WaitUntilIdle());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Documents and ensures current behavior for setting `nullptr` service objects
|
||||||
|
// for "AllowDefaultInitialization" services.
|
||||||
|
// - It's allowed.
|
||||||
|
// - It disables creation of "AllowDefaultInitialization" service objects, hence
|
||||||
|
// in service unavaialbility.
|
||||||
|
TEST(AllowDefaultInitializationGraphServiceTest,
|
||||||
|
NullServiceObjectIsAllowAndResultsInServiceUnavailability) {
|
||||||
|
CalculatorGraphConfig config =
|
||||||
|
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"pb(
|
||||||
|
node { calculator: 'FailOnUnavailableServiceCalculator' }
|
||||||
|
)pb");
|
||||||
|
|
||||||
|
CalculatorGraph graph;
|
||||||
|
std::shared_ptr<TestServiceData> object = nullptr;
|
||||||
|
MP_ASSERT_OK(
|
||||||
|
graph.SetServiceObject(kTestServiceAllowDefaultInitialization, object));
|
||||||
|
MP_ASSERT_OK(graph.Initialize(config));
|
||||||
|
MP_ASSERT_OK(graph.StartRun({}));
|
||||||
|
EXPECT_THAT(graph.WaitUntilIdle(),
|
||||||
|
StatusIs(absl::StatusCode::kInternal,
|
||||||
|
HasSubstr("Service is unavailable.")));
|
||||||
|
}
|
||||||
|
|
||||||
|
const GraphService<TestServiceData> kTestServiceDisallowDefaultInitialization(
|
||||||
|
"kTestServiceDisallowDefaultInitialization",
|
||||||
|
GraphServiceBase::kDisallowDefaultInitialization);
|
||||||
|
|
||||||
|
class FailOnUnavailableOptionalDisallowDefaultInitServiceCalculator
|
||||||
|
: public CalculatorBase {
|
||||||
|
public:
|
||||||
|
static absl::Status GetContract(CalculatorContract* cc) {
|
||||||
|
cc->UseService(kTestServiceDisallowDefaultInitialization).Optional();
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
absl::Status Open(CalculatorContext* cc) final {
|
||||||
|
RET_CHECK(
|
||||||
|
cc->Service(kTestServiceDisallowDefaultInitialization).IsAvailable())
|
||||||
|
<< "Service is unavailable.";
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
absl::Status Process(CalculatorContext* cc) final { return absl::OkStatus(); }
|
||||||
|
};
|
||||||
|
REGISTER_CALCULATOR(
|
||||||
|
FailOnUnavailableOptionalDisallowDefaultInitServiceCalculator);
|
||||||
|
|
||||||
|
// Documents and ensures current behavior for requesting optional
|
||||||
|
// "DisallowDefaultInitialization" services:
|
||||||
|
// - Service object is not created by default.
|
||||||
|
TEST(DisallowDefaultInitializationGraphServiceTest,
|
||||||
|
ServiceIsUnavailableWithOptionalUse) {
|
||||||
|
CalculatorGraphConfig config = mediapipe::ParseTextProtoOrDie<
|
||||||
|
CalculatorGraphConfig>(R"pb(
|
||||||
|
node {
|
||||||
|
calculator: 'FailOnUnavailableOptionalDisallowDefaultInitServiceCalculator'
|
||||||
|
}
|
||||||
|
)pb");
|
||||||
|
|
||||||
|
CalculatorGraph graph;
|
||||||
|
MP_ASSERT_OK(graph.Initialize(config));
|
||||||
|
MP_ASSERT_OK(graph.StartRun({}));
|
||||||
|
EXPECT_THAT(graph.WaitUntilIdle(),
|
||||||
|
StatusIs(absl::StatusCode::kInternal,
|
||||||
|
HasSubstr("Service is unavailable.")));
|
||||||
|
}
|
||||||
|
|
||||||
|
class UseDisallowDefaultInitServiceCalculator : public CalculatorBase {
|
||||||
|
public:
|
||||||
|
static absl::Status GetContract(CalculatorContract* cc) {
|
||||||
|
cc->UseService(kTestServiceDisallowDefaultInitialization);
|
||||||
|
return absl::OkStatus();
|
||||||
|
}
|
||||||
|
absl::Status Open(CalculatorContext* cc) final { return absl::OkStatus(); }
|
||||||
|
absl::Status Process(CalculatorContext* cc) final { return absl::OkStatus(); }
|
||||||
|
};
|
||||||
|
REGISTER_CALCULATOR(UseDisallowDefaultInitServiceCalculator);
|
||||||
|
|
||||||
|
// Documents and ensures current behavior for requesting
|
||||||
|
// "DisallowDefaultInitialization" services:
|
||||||
|
// - Service object is not created by default.
|
||||||
|
// - Graph run fails.
|
||||||
|
TEST(DisallowDefaultInitializationGraphServiceTest,
|
||||||
|
StartRunFailsMissingService) {
|
||||||
|
CalculatorGraphConfig config =
|
||||||
|
mediapipe::ParseTextProtoOrDie<CalculatorGraphConfig>(R"pb(
|
||||||
|
node { calculator: 'UseDisallowDefaultInitServiceCalculator' }
|
||||||
|
)pb");
|
||||||
|
|
||||||
|
CalculatorGraph graph;
|
||||||
|
MP_ASSERT_OK(graph.Initialize(config));
|
||||||
|
EXPECT_THAT(graph.StartRun({}),
|
||||||
|
StatusIs(absl::StatusCode::kInternal,
|
||||||
|
HasSubstr("was not provided and cannot be created")));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
} // namespace mediapipe
|
} // namespace mediapipe
|
||||||
|
|
Loading…
Reference in New Issue
Block a user