Skip to content

Commit f7cc2e5

Browse files
motiz88meta-codesync[bot]
authored andcommitted
Add tests for Tracing domain reporting of network requests (facebook#54128)
Summary: Pull Request resolved: facebook#54128 Changelog: [Internal] Adds an integration test for `NetworkReporter`'s CDP Tracing domain output (via `PerformanceTracer` behind the scenes), i.e. the traces that power the Network track in the Performance panel in React Native DevTools. The test covers the `Tracing` and `Network` domains being enabled simultaneously, as well as `Tracing` on its own. Reviewed By: huntie Differential Revision: D84337901 fbshipit-source-id: f82af33575806fc3b99636cdb1eb9803c04c8c07
1 parent 708f527 commit f7cc2e5

File tree

2 files changed

+250
-13
lines changed

2 files changed

+250
-13
lines changed

packages/react-native/ReactCommon/jsinspector-modern/tests/NetworkReporterTest.cpp

Lines changed: 243 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,26 +19,29 @@ namespace facebook::react::jsinspector_modern {
1919

2020
namespace {
2121

22-
struct Params {
22+
struct NetworkReporterTestParams {
2323
bool enableNetworkEventReporting;
2424
};
2525

2626
} // namespace
2727

2828
/**
2929
* A test fixture for the way the internal NetworkReporter API interacts with
30-
* the CDP Network domain.
30+
* the CDP Network and Tracing domains.
3131
*/
32-
class NetworkReporterTest : public JsiIntegrationPortableTestBase<
33-
JsiIntegrationTestHermesEngineAdapter,
34-
folly::QueuedImmediateExecutor>,
35-
public WithParamInterface<Params> {
32+
template <typename Params>
33+
requires std::convertible_to<Params, NetworkReporterTestParams>
34+
class NetworkReporterTestBase : public JsiIntegrationPortableTestBase<
35+
JsiIntegrationTestHermesEngineAdapter,
36+
folly::QueuedImmediateExecutor>,
37+
public WithParamInterface<Params> {
3638
protected:
37-
NetworkReporterTest()
39+
NetworkReporterTestBase()
3840
: JsiIntegrationPortableTestBase({
3941
.networkInspectionEnabled = true,
4042
.enableNetworkEventReporting =
41-
GetParam().enableNetworkEventReporting,
43+
WithParamInterface<Params>::GetParam()
44+
.enableNetworkEventReporting,
4245
}) {}
4346

4447
void SetUp() override {
@@ -65,6 +68,58 @@ class NetworkReporterTest : public JsiIntegrationPortableTestBase<
6568
urlMatcher);
6669
}
6770

71+
void startTracing() {
72+
this->expectMessageFromPage(JsonEq(R"({
73+
"id": 1,
74+
"result": {}
75+
})"));
76+
77+
this->toPage_->sendMessage(R"({
78+
"id": 1,
79+
"method": "Tracing.start"
80+
})");
81+
}
82+
83+
/**
84+
* Helper method to end tracing and collect all trace events from potentially
85+
* multiple chunked Tracing.dataCollected messages.
86+
* \returns A vector containing all collected trace events
87+
*/
88+
std::vector<folly::dynamic> endTracingAndCollectEvents() {
89+
InSequence s;
90+
91+
this->expectMessageFromPage(JsonEq(R"({
92+
"id": 1,
93+
"result": {}
94+
})"));
95+
96+
std::vector<folly::dynamic> allTraceEvents;
97+
98+
EXPECT_CALL(
99+
fromPage(),
100+
onMessage(JsonParsed(AtJsonPtr("/method", "Tracing.dataCollected"))))
101+
.Times(AtLeast(1))
102+
.WillRepeatedly(Invoke([&allTraceEvents](const std::string& message) {
103+
auto parsedMessage = folly::parseJson(message);
104+
auto& events = parsedMessage.at("params").at("value");
105+
allTraceEvents.insert(
106+
allTraceEvents.end(),
107+
std::make_move_iterator(events.begin()),
108+
std::make_move_iterator(events.end()));
109+
}));
110+
111+
this->expectMessageFromPage(JsonParsed(AllOf(
112+
AtJsonPtr("/method", "Tracing.tracingComplete"),
113+
AtJsonPtr("/params/dataLossOccurred", false))));
114+
115+
this->toPage_->sendMessage(R"({
116+
"id": 1,
117+
"method": "Tracing.end"
118+
})");
119+
120+
return allTraceEvents;
121+
}
122+
68123
private:
69124
std::optional<std::string> getScriptUrlById(const std::string& scriptId) {
70125
auto it = scriptUrlsById_.find(scriptId);
@@ -77,6 +132,8 @@ class NetworkReporterTest : public JsiIntegrationPortableTestBase<
77132
std::unordered_map<std::string, std::string> scriptUrlsById_;
78133
};
79134

135+
using NetworkReporterTest = NetworkReporterTestBase<NetworkReporterTestParams>;
136+
80137
TEST_P(NetworkReporterTest, testNetworkEnableDisable) {
81138
InSequence s;
82139

@@ -581,12 +638,186 @@ TEST_P(NetworkReporterTest, testCreateRequestIdWithoutNetworkDomain) {
581638
EXPECT_NE(id1, id2);
582639
}
583640

584-
static const auto paramValues = testing::Values(
585-
Params{.enableNetworkEventReporting = true},
586-
Params{
641+
struct NetworkReporterTracingTestParams {
642+
bool enableNetworkEventReporting;
643+
bool enableNetworkDomain;
644+
645+
operator NetworkReporterTestParams() const {
646+
return NetworkReporterTestParams{
647+
.enableNetworkEventReporting = enableNetworkEventReporting,
648+
};
649+
}
650+
};
651+
652+
using NetworkReporterTracingTest =
653+
NetworkReporterTestBase<NetworkReporterTracingTestParams>;
654+
655+
TEST_P(
656+
NetworkReporterTracingTest,
657+
testReportsToTracingDomainPlusNetworkDomain) {
658+
InSequence s;
659+
660+
this->startTracing();
661+
662+
if (GetParam().enableNetworkDomain) {
663+
this->expectMessageFromPage(JsonEq(R"({
664+
"id": 1,
665+
"result": {}
666+
})"));
667+
this->toPage_->sendMessage(R"({
668+
"id": 1,
669+
"method": "Network.enable"
670+
})");
671+
672+
this->expectMessageFromPage(JsonParsed(AllOf(
673+
AtJsonPtr("/method", "Network.requestWillBeSent"),
674+
AtJsonPtr("/params/requestId", "trace-events-request"),
675+
AtJsonPtr("/params/loaderId", ""),
676+
AtJsonPtr("/params/documentURL", "mobile"),
677+
AtJsonPtr("/params/request/url", "https://trace.example.com/events"),
678+
AtJsonPtr("/params/request/method", "GET"),
679+
AtJsonPtr("/params/request/headers/Accept", "application/json"),
680+
AtJsonPtr("/params/timestamp", Gt(0)),
681+
AtJsonPtr("/params/wallTime", Gt(0)),
682+
AtJsonPtr("/params/initiator/type", "script"),
683+
AtJsonPtr("/params/redirectHasExtraInfo", false))));
684+
685+
this->expectMessageFromPage(JsonParsed(AllOf(
686+
AtJsonPtr("/method", "Network.requestWillBeSentExtraInfo"),
687+
AtJsonPtr("/params/requestId", "trace-events-request"),
688+
AtJsonPtr("/params/associatedCookies", "[]"_json),
689+
AtJsonPtr("/params/headers", "{}"_json),
690+
AtJsonPtr("/params/connectTiming/requestTime", Gt(0)))));
691+
692+
this->expectMessageFromPage(JsonParsed(AllOf(
693+
AtJsonPtr("/method", "Network.responseReceived"),
694+
AtJsonPtr("/params/requestId", "trace-events-request"),
695+
AtJsonPtr("/params/loaderId", ""),
696+
AtJsonPtr("/params/timestamp", Gt(0)),
697+
AtJsonPtr("/params/type", "XHR"),
698+
AtJsonPtr("/params/response/url", "https://trace.example.com/events"),
699+
AtJsonPtr("/params/response/status", 200),
700+
AtJsonPtr("/params/response/statusText", "OK"),
701+
AtJsonPtr("/params/response/headers/Content-Type", "application/json"),
702+
AtJsonPtr("/params/response/mimeType", "application/json"),
703+
AtJsonPtr("/params/response/encodedDataLength", 1024),
704+
AtJsonPtr("/params/hasExtraInfo", false))));
705+
706+
this->expectMessageFromPage(JsonParsed(AllOf(
707+
AtJsonPtr("/method", "Network.loadingFinished"),
708+
AtJsonPtr("/params/requestId", "trace-events-request"),
709+
AtJsonPtr("/params/timestamp", Gt(0)),
710+
AtJsonPtr("/params/encodedDataLength", 1024))));
711+
}
712+
713+
NetworkReporter::getInstance().reportRequestStart(
714+
"trace-events-request",
715+
{
716+
.url = "https://trace.example.com/events",
717+
.httpMethod = "GET",
718+
.headers = Headers{{"Accept", "application/json"}},
719+
},
720+
0,
721+
std::nullopt);
722+
723+
NetworkReporter::getInstance().reportConnectionTiming(
724+
"trace-events-request", std::nullopt);
725+
726+
NetworkReporter::getInstance().reportResponseStart(
727+
"trace-events-request",
728+
{
729+
.url = "https://trace.example.com/events",
730+
.statusCode = 200,
731+
.headers = Headers{{"Content-Type", "application/json"}},
732+
},
733+
1024);
734+
735+
NetworkReporter::getInstance().reportResponseEnd(
736+
"trace-events-request", 1024);
737+
738+
auto allTraceEvents = endTracingAndCollectEvents();
739+
740+
EXPECT_THAT(
741+
allTraceEvents,
742+
Contains(AllOf(
743+
AtJsonPtr("/name", "ResourceSendRequest"),
744+
AtJsonPtr("/cat", "devtools.timeline"),
745+
AtJsonPtr("/ph", "I"),
746+
AtJsonPtr("/s", "t"),
747+
AtJsonPtr("/tid", oscompat::getCurrentThreadId()),
748+
AtJsonPtr("/pid", oscompat::getCurrentProcessId()),
749+
AtJsonPtr("/args/data/initiator", "{}"_json),
750+
AtJsonPtr("/args/data/requestId", "trace-events-request"),
751+
AtJsonPtr("/args/data/url", "https://trace.example.com/events"),
752+
AtJsonPtr("/args/data/requestMethod", "GET"),
753+
AtJsonPtr("/args/data/priority", "VeryHigh"),
754+
AtJsonPtr("/args/data/renderBlocking", "non_blocking"),
755+
AtJsonPtr("/args/data/resourceType", "Other"))));
756+
757+
EXPECT_THAT(
758+
allTraceEvents,
759+
Contains(AllOf(
760+
AtJsonPtr("/name", "ResourceReceiveResponse"),
761+
AtJsonPtr("/cat", "devtools.timeline"),
762+
AtJsonPtr("/ph", "I"),
763+
AtJsonPtr("/s", "t"),
764+
AtJsonPtr("/tid", oscompat::getCurrentThreadId()),
765+
AtJsonPtr("/pid", oscompat::getCurrentProcessId()),
766+
AtJsonPtr("/ts", Gt(0)),
767+
AtJsonPtr("/args/data/requestId", "trace-events-request"),
768+
AtJsonPtr("/args/data/statusCode", 200),
769+
AtJsonPtr("/args/data/mimeType", "application/json"),
770+
AtJsonPtr("/args/data/protocol", "h2"),
771+
AtJsonPtr("/args/data/encodedDataLength", 1024),
772+
AtJsonPtr(
773+
"/args/data/headers",
774+
R"([{ "name": "Content-Type", "value": "application/json" }])"_json),
775+
AtJsonPtr(
776+
"/args/data/timing",
777+
AllOf(
778+
AtJsonPtr("/requestTime", Ge(0)),
779+
AtJsonPtr("/sendStart", Ge(0)),
780+
AtJsonPtr("/sendEnd", Ge(0)),
781+
AtJsonPtr("/receiveHeadersStart", Ge(0)),
782+
AtJsonPtr("/receiveHeadersEnd", Ge(0)))))));
783+
784+
EXPECT_THAT(
785+
allTraceEvents,
786+
Contains(AllOf(
787+
AtJsonPtr("/name", "ResourceFinish"),
788+
AtJsonPtr("/cat", "devtools.timeline"),
789+
AtJsonPtr("/ph", "I"),
790+
AtJsonPtr("/s", "t"),
791+
AtJsonPtr("/tid", oscompat::getCurrentThreadId()),
792+
AtJsonPtr("/pid", oscompat::getCurrentProcessId()),
793+
AtJsonPtr("/args/data/requestId", "trace-events-request"),
794+
AtJsonPtr("/args/data/encodedDataLength", 1024),
795+
AtJsonPtr("/args/data/decodedBodyLength", 0),
796+
AtJsonPtr("/args/data/didFail", false))));
797+
}
798+
799+
static const auto networkReporterTestParamValues = testing::Values(
800+
NetworkReporterTestParams{.enableNetworkEventReporting = true},
801+
NetworkReporterTestParams{
587802
.enableNetworkEventReporting = false,
588803
});
589804

590-
INSTANTIATE_TEST_SUITE_P(NetworkReporterTest, NetworkReporterTest, paramValues);
805+
static const auto networkReporterTracingTestParamValues = testing::Values(
806+
NetworkReporterTracingTestParams{
807+
.enableNetworkEventReporting = true,
808+
.enableNetworkDomain = true},
809+
NetworkReporterTracingTestParams{
810+
.enableNetworkEventReporting = true,
811+
.enableNetworkDomain = false});
812+
813+
INSTANTIATE_TEST_SUITE_P(
814+
NetworkReporterTest,
815+
NetworkReporterTest,
816+
networkReporterTestParamValues);
817+
818+
INSTANTIATE_TEST_SUITE_P(
819+
NetworkReporterTracingTest,
820+
NetworkReporterTracingTest,
821+
networkReporterTracingTestParamValues);
591822

592823
} // namespace facebook::react::jsinspector_modern

packages/react-native/ReactCommon/jsinspector-modern/tests/engines/JsiIntegrationTestHermesEngineAdapter.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,13 @@ JsiIntegrationTestHermesEngineAdapter::JsiIntegrationTestHermesEngineAdapter(
1717
::hermes::vm::CompilationMode::ForceLazyCompilation)
1818
.build())},
1919
jsExecutor_{jsExecutor},
20-
runtimeTargetDelegate_{runtime_} {}
20+
runtimeTargetDelegate_{runtime_} {
21+
// NOTE: In React Native, registerForProfiling is called by
22+
// HermesInstance::unstable_initializeOnJsThread, called from
23+
// ReactInstance::initializeRuntime. Ideally, we should figure out how to
24+
// manages this from inside the CDP backend,
25+
runtime_->registerForProfiling();
26+
}
2127

2228
RuntimeTargetDelegate&
2329
JsiIntegrationTestHermesEngineAdapter::getRuntimeTargetDelegate() {

0 commit comments

Comments
 (0)