55using System . Collections . Generic ;
66using System . IO ;
77using System . Linq ;
8- using System . Text . Json ;
8+ using System . Text ;
99using System . Threading . Tasks ;
1010using Elastic . Transport . IntegrationTests . Plumbing ;
1111using Elastic . Transport . Products . Elasticsearch ;
@@ -33,23 +33,6 @@ public async Task StreamResponse_ShouldNotBeDisposed()
3333 _ = sr . ReadToEndAsync ( ) ;
3434 }
3535
36- //[Fact]
37- //public async Task StreamResponse_MemoryStreamShouldNotBeDisposed()
38- //{
39- // var nodePool = new SingleNodePool(Server.Uri);
40- // var memoryStreamFactory = new TrackMemoryStreamFactory();
41- // var config = new TransportConfiguration(nodePool, productRegistration: new ElasticsearchProductRegistration(typeof(Clients.Elasticsearch.ElasticsearchClient)))
42- // .MemoryStreamFactory(memoryStreamFactory);
43-
44- // var transport = new DistributedTransport(config);
45-
46- // _ = await transport.PostAsync<StreamResponse>(Path, PostData.String("{}"));
47-
48- // var memoryStream = memoryStreamFactory.Created.Last();
49-
50- // memoryStream.IsDisposed.Should().BeFalse();
51- //}
52-
5336 [ Fact ]
5437 public async Task StreamResponse_MemoryStreamShouldNotBeDisposed ( )
5538 {
@@ -63,9 +46,9 @@ public async Task StreamResponse_MemoryStreamShouldNotBeDisposed()
6346
6447 _ = await transport . PostAsync < StreamResponse > ( Path , PostData . String ( "{}" ) ) ;
6548
66- var memoryStream = memoryStreamFactory . Created . Last ( ) ;
67-
68- memoryStream . IsDisposed . Should ( ) . BeFalse ( ) ;
49+ // When disable direct streaming, we have 1 for the original content, 1 for the buffered request bytes and the last for the buffered response
50+ memoryStreamFactory . Created . Count . Should ( ) . Be ( 3 ) ;
51+ memoryStreamFactory . Created . Last ( ) . IsDisposed . Should ( ) . BeFalse ( ) ;
6952 }
7053
7154 [ Fact ]
@@ -80,13 +63,36 @@ public async Task StringResponse_MemoryStreamShouldBeDisposed()
8063
8164 _ = await transport . PostAsync < StringResponse > ( Path , PostData . String ( "{}" ) ) ;
8265
83- var memoryStream = memoryStreamFactory . Created . Last ( ) ;
66+ memoryStreamFactory . Created . Count . Should ( ) . Be ( 2 ) ;
67+ foreach ( var memoryStream in memoryStreamFactory . Created )
68+ {
69+ memoryStream . IsDisposed . Should ( ) . BeTrue ( ) ;
70+ }
71+ }
72+
73+ [ Fact ]
74+ public async Task WhenInvalidJson_MemoryStreamShouldBeDisposed ( )
75+ {
76+ var nodePool = new SingleNodePool ( Server . Uri ) ;
77+ var memoryStreamFactory = new TrackMemoryStreamFactory ( ) ;
78+ var config = new TransportConfiguration ( nodePool , productRegistration : new ElasticsearchProductRegistration ( typeof ( Clients . Elasticsearch . ElasticsearchClient ) ) )
79+ . MemoryStreamFactory ( memoryStreamFactory )
80+ . DisableDirectStreaming ( true ) ;
81+
82+ var transport = new DistributedTransport ( config ) ;
83+
84+ var payload = new Payload { ResponseJsonString = " " } ;
85+ _ = await transport . PostAsync < TestResponse > ( Path , PostData . Serializable ( payload ) ) ;
8486
85- memoryStream . IsDisposed . Should ( ) . BeTrue ( ) ;
87+ memoryStreamFactory . Created . Count . Should ( ) . Be ( 3 ) ;
88+ foreach ( var memoryStream in memoryStreamFactory . Created )
89+ {
90+ memoryStream . IsDisposed . Should ( ) . BeTrue ( ) ;
91+ }
8692 }
8793
8894 [ Fact ]
89- public async Task Response_MemoryStreamShouldBeDisposed ( )
95+ public async Task WhenNoContent_MemoryStreamShouldBeDisposed ( )
9096 {
9197 var nodePool = new SingleNodePool ( Server . Uri ) ;
9298 var memoryStreamFactory = new TrackMemoryStreamFactory ( ) ;
@@ -95,11 +101,37 @@ public async Task Response_MemoryStreamShouldBeDisposed()
95101
96102 var transport = new DistributedTransport ( config ) ;
97103
98- _ = await transport . PostAsync < TestResponse > ( Path , PostData . String ( "{}" ) ) ;
104+ var payload = new Payload { ResponseJsonString = "" , StatusCode = 204 } ;
105+ _ = await transport . PostAsync < TestResponse > ( Path , PostData . Serializable ( payload ) ) ;
99106
100- var memoryStream = memoryStreamFactory . Created . Last ( ) ;
107+ // We expect one for sending the request payload, but as the response is 204, we shouldn't
108+ // see other memory streams being created for the response.
109+ memoryStreamFactory . Created . Count . Should ( ) . Be ( 1 ) ;
110+ foreach ( var memoryStream in memoryStreamFactory . Created )
111+ {
112+ memoryStream . IsDisposed . Should ( ) . BeTrue ( ) ;
113+ }
114+ }
115+
116+ [ Fact ]
117+ public async Task PlainText_MemoryStreamShouldBeDisposed ( )
118+ {
119+ var nodePool = new SingleNodePool ( Server . Uri ) ;
120+ var memoryStreamFactory = new TrackMemoryStreamFactory ( ) ;
121+ var config = new TransportConfiguration ( nodePool , productRegistration : new ElasticsearchProductRegistration ( typeof ( Clients . Elasticsearch . ElasticsearchClient ) ) )
122+ . MemoryStreamFactory ( memoryStreamFactory )
123+ . DisableDirectStreaming ( true ) ;
124+
125+ var transport = new DistributedTransport ( config ) ;
126+
127+ var payload = new Payload { ResponseJsonString = "text" , ContentType = "text/plain" } ;
128+ _ = await transport . PostAsync < TestResponse > ( Path , PostData . Serializable ( payload ) ) ;
101129
102- memoryStream . IsDisposed . Should ( ) . BeTrue ( ) ;
130+ memoryStreamFactory . Created . Count . Should ( ) . Be ( 3 ) ;
131+ foreach ( var memoryStream in memoryStreamFactory . Created )
132+ {
133+ memoryStream . IsDisposed . Should ( ) . BeTrue ( ) ;
134+ }
103135 }
104136
105137 private class TestResponse : TransportResponse
@@ -150,9 +182,27 @@ public override MemoryStream Create(byte[] bytes, int index, int count)
150182 }
151183}
152184
185+ public class Payload
186+ {
187+ public string ResponseJsonString { get ; set ; } = "{}" ;
188+ public string ContentType { get ; set ; } = "application/json" ;
189+ public int StatusCode { get ; set ; } = 200 ;
190+ }
191+
153192[ ApiController , Route ( "[controller]" ) ]
154193public class StreamResponseController : ControllerBase
155194{
156195 [ HttpPost ]
157- public Task < JsonElement > Post ( [ FromBody ] JsonElement body ) => Task . FromResult ( body ) ;
196+ public async Task < ActionResult > Post ( [ FromBody ] Payload payload )
197+ {
198+ Response . ContentType = payload . ContentType ;
199+
200+ if ( payload . StatusCode != 204 )
201+ {
202+ await Response . BodyWriter . WriteAsync ( Encoding . UTF8 . GetBytes ( payload . ResponseJsonString ) ) ;
203+ await Response . BodyWriter . CompleteAsync ( ) ;
204+ }
205+
206+ return StatusCode ( payload . StatusCode ) ;
207+ }
158208}
0 commit comments