@@ -892,3 +892,93 @@ async fn usage_reporting_exclude_runs_before_at_least_once() {
892892 let total_ops = mock. total_operations_count ( ) . await ;
893893 assert_eq ! ( total_ops, 2 ) ;
894894}
895+
896+ /// Test that an operation resolved from a persisted document reports the resolved
897+ /// document id as `persistedDocumentHash`, while a plain query reports none.
898+ /// https://github.com/graphql-hive/router/issues/1343
899+ #[ ntex:: test]
900+ async fn usage_reporting_includes_persisted_document_hash ( ) {
901+ let supergraph_path =
902+ std:: path:: PathBuf :: from ( env ! ( "CARGO_MANIFEST_DIR" ) ) . join ( "supergraph.graphql" ) ;
903+ let supergraph_path = supergraph_path. to_str ( ) . unwrap ( ) ;
904+
905+ let mock = MockUsageEndpoint :: start ( ) ;
906+ let usage_endpoint = & mock. address ;
907+
908+ let doc_id = "app~1.0.0~sha256:usage123" ;
909+ let manifest = tempfile:: NamedTempFile :: new ( ) . expect ( "failed to create manifest file" ) ;
910+ std:: fs:: write (
911+ manifest. path ( ) ,
912+ sonic_rs:: to_string ( & sonic_rs:: json!( { doc_id: "{ users { id } }" } ) )
913+ . expect ( "failed to serialize manifest" ) ,
914+ )
915+ . expect ( "failed to write manifest" ) ;
916+
917+ let subgraphs = TestSubgraphs :: builder ( ) . build ( ) . start ( ) . await ;
918+
919+ let router = TestRouter :: builder ( )
920+ . inline_config ( format ! (
921+ r#"
922+ supergraph:
923+ source: file
924+ path: {supergraph_path}
925+
926+ persisted_documents:
927+ enabled: true
928+ storage:
929+ type: file
930+ path: "{manifest_path}"
931+
932+ telemetry:
933+ hive:
934+ token: test-token
935+ usage_reporting:
936+ enabled: true
937+ endpoint: {usage_endpoint}
938+ buffer_size: 1
939+ flush_interval: 100ms
940+ "# ,
941+ manifest_path = manifest. path( ) . display( ) ,
942+ ) )
943+ . with_subgraphs ( & subgraphs)
944+ . build ( )
945+ . start ( )
946+ . await ;
947+
948+ // Resolved from the persisted document manifest.
949+ let res = router
950+ . send_post_request ( "/graphql" , sonic_rs:: json!( { "documentId" : doc_id } ) , None )
951+ . await ;
952+ assert ! ( res. status( ) . is_success( ) ) ;
953+
954+ mock. wait_for_reports ( 1 ) . await ;
955+ let reports = mock. reports ( ) . await ;
956+ let operations = reports[ 0 ] [ "operations" ]
957+ . as_array ( )
958+ . expect ( "report should contain operations" ) ;
959+ assert_eq ! ( operations. len( ) , 1 ) ;
960+ assert_eq ! (
961+ operations[ 0 ] [ "persistedDocumentHash" ] . as_str( ) ,
962+ Some ( doc_id) ,
963+ "operation should carry the resolved persisted document id: {}" ,
964+ reports[ 0 ]
965+ ) ;
966+
967+ // A plain query (allowed since require_id is off) must not carry a hash.
968+ let res = router
969+ . send_graphql_request ( "{ users { id } }" , None , None )
970+ . await ;
971+ assert ! ( res. status( ) . is_success( ) ) ;
972+
973+ mock. wait_for_reports ( 2 ) . await ;
974+ let reports = mock. reports ( ) . await ;
975+ let operations = reports[ 1 ] [ "operations" ]
976+ . as_array ( )
977+ . expect ( "report should contain operations" ) ;
978+ assert_eq ! ( operations. len( ) , 1 ) ;
979+ assert ! (
980+ operations[ 0 ] [ "persistedDocumentHash" ] . is_null( ) ,
981+ "plain query must not report a persisted document hash: {}" ,
982+ reports[ 1 ]
983+ ) ;
984+ }
0 commit comments