11using Grpc . Core ;
22using Moq ;
33using Xunit ;
4+ using Ydb . Issue ;
45using Ydb . Sdk . Services . Topic ;
56using Ydb . Sdk . Services . Topic . Writer ;
67using Ydb . Topic ;
8+ using Codec = Ydb . Sdk . Services . Topic . Codec ;
79
810namespace Ydb . Sdk . Tests . Topic ;
911
10- using WriterStream = BidirectionalStream < StreamWriteMessage . Types . FromClient , StreamWriteMessage . Types . FromServer > ;
12+ using WriterStream = IBidirectionalStream < StreamWriteMessage . Types . FromClient , StreamWriteMessage . Types . FromServer > ;
1113
1214public class WriterMockTests
1315{
@@ -20,24 +22,219 @@ public WriterMockTests()
2022 It . IsAny < Method < StreamWriteMessage . Types . FromClient , StreamWriteMessage . Types . FromServer > > ( ) ,
2123 It . IsAny < GrpcRequestSettings > ( ) )
2224 ) . Returns ( _mockStream . Object ) ;
25+
26+ _mockIDriver . Setup ( driver => driver . LoggerFactory ) . Returns ( Utils . GetLoggerFactory ) ;
2327 }
2428
25- // [Fact]
26- public async Task NotStarted_Failed_Test ( )
29+ [ Fact ]
30+ public async Task Initialize_WhenStreamIsClosedByServer_ThrowWriterExceptionOnWriteAsyncAndTryNextInitialize ( )
2731 {
2832 var moveNextTry = new TaskCompletionSource < bool > ( ) ;
33+ var taskNextComplete = new TaskCompletionSource ( ) ;
2934
30- _mockStream
31- . Setup ( stream => stream . Write ( It . IsAny < StreamWriteMessage . Types . FromClient > ( ) ) )
35+ _mockStream . Setup ( stream => stream . Write ( It . IsAny < StreamWriteMessage . Types . FromClient > ( ) ) )
3236 . Returns ( Task . CompletedTask ) ;
33-
3437 _mockStream . SetupSequence ( stream => stream . MoveNextAsync ( ) )
3538 . ReturnsAsync ( false )
36- . Returns ( new ValueTask < bool > ( moveNextTry . Task ) ) ; // For retry
39+ . Returns ( ( ) =>
40+ {
41+ taskNextComplete . SetResult ( ) ;
42+ return new ValueTask < bool > ( moveNextTry . Task ) ;
43+ } ) ;
3744
3845 using var writer = new WriterBuilder < int > ( _mockIDriver . Object , new WriterConfig ( "/topic" )
3946 { ProducerId = "producerId" } ) . Build ( ) ;
4047
41- await Assert . ThrowsAsync < WriterException > ( ( ) => writer . WriteAsync ( 100 ) ) ;
48+ Assert . Equal ( "Stream unexpectedly closed by YDB server. " +
49+ "Current InitRequest: { \" path\" : \" /topic\" , \" producerId\" : \" producerId\" }" ,
50+ ( await Assert . ThrowsAsync < WriterException > ( ( ) => writer . WriteAsync ( 100 ) ) ) . Message ) ;
51+
52+ await taskNextComplete . Task ;
53+ // check attempt repeated!!!
54+ _mockStream . Verify ( stream => stream . Write ( It . IsAny < StreamWriteMessage . Types . FromClient > ( ) ) , Times . Exactly ( 2 ) ) ;
55+ _mockStream . Verify ( stream => stream . MoveNextAsync ( ) , Times . Exactly ( 2 ) ) ;
56+ }
57+
58+ [ Fact ]
59+ public async Task Initialize_WhenFailWriteMessage_ThrowWriterExceptionOnWriteAsyncAndTryNextInitialize ( )
60+ {
61+ var taskSource = new TaskCompletionSource ( ) ;
62+ var taskNextComplete = new TaskCompletionSource ( ) ;
63+ _mockStream . SetupSequence ( stream => stream . Write ( It . IsAny < StreamWriteMessage . Types . FromClient > ( ) ) )
64+ . ThrowsAsync ( new Driver . TransportException ( new RpcException ( Grpc . Core . Status . DefaultCancelled ) ) )
65+ . Returns ( ( ) =>
66+ {
67+ taskNextComplete . SetResult ( ) ;
68+ return taskSource . Task ;
69+ } ) ;
70+
71+ using var writer = new WriterBuilder < string > ( _mockIDriver . Object , new WriterConfig ( "/topic" )
72+ { ProducerId = "producerId" } ) . Build ( ) ;
73+
74+ var writerException = await Assert . ThrowsAsync < WriterException > ( ( ) => writer . WriteAsync ( "abacaba" ) ) ;
75+ Assert . Equal ( "Transport error on creating write session" , writerException . Message ) ;
76+ Assert . Equal ( StatusCode . Cancelled , writerException . Status . StatusCode ) ;
77+
78+ await taskNextComplete . Task ;
79+ // check attempt repeated!!!
80+ _mockStream . Verify ( stream => stream . Write ( It . IsAny < StreamWriteMessage . Types . FromClient > ( ) ) , Times . Exactly ( 2 ) ) ;
81+ }
82+
83+ [ Fact ]
84+ public async Task Initialize_WhenFailMoveNextAsync_ThrowWriterExceptionOnWriteAsyncAndTryNextInitialize ( )
85+ {
86+ var taskSource = new TaskCompletionSource < bool > ( ) ;
87+ var taskNextComplete = new TaskCompletionSource ( ) ;
88+ _mockStream . Setup ( stream => stream . Write ( It . IsAny < StreamWriteMessage . Types . FromClient > ( ) ) )
89+ . Returns ( Task . CompletedTask ) ;
90+ _mockStream . SetupSequence ( stream => stream . MoveNextAsync ( ) )
91+ . ThrowsAsync ( new Driver . TransportException (
92+ new RpcException ( new Grpc . Core . Status ( Grpc . Core . StatusCode . DeadlineExceeded , "Some message" ) ) ) )
93+ . Returns ( ( ) =>
94+ {
95+ taskNextComplete . SetResult ( ) ;
96+ return new ValueTask < bool > ( taskSource . Task ) ;
97+ } ) ;
98+
99+ using var writer = new WriterBuilder < string > ( _mockIDriver . Object , new WriterConfig ( "/topic" )
100+ { ProducerId = "producerId" } ) . Build ( ) ;
101+
102+ var writerException = await Assert . ThrowsAsync < WriterException > ( ( ) => writer . WriteAsync ( "abacaba" ) ) ;
103+ Assert . Equal ( "Transport error on creating write session" , writerException . Message ) ;
104+ Assert . Equal ( StatusCode . ClientTransportTimeout , writerException . Status . StatusCode ) ;
105+
106+ await taskNextComplete . Task ;
107+ // check attempt repeated!!!
108+ _mockStream . Verify ( stream => stream . Write ( It . IsAny < StreamWriteMessage . Types . FromClient > ( ) ) , Times . Exactly ( 2 ) ) ;
109+ _mockStream . Verify ( stream => stream . MoveNextAsync ( ) , Times . Exactly ( 2 ) ) ;
42110 }
111+
112+ [ Fact ]
113+ public async Task Initialize_WhenInitResponseNotSuccess_ThrowWriterExceptionOnWriteAsyncAndTryNextInitialize ( )
114+ {
115+ var taskSource = new TaskCompletionSource < bool > ( ) ;
116+ var taskNextComplete = new TaskCompletionSource ( ) ;
117+ _mockStream . Setup ( stream => stream . Write ( It . IsAny < StreamWriteMessage . Types . FromClient > ( ) ) )
118+ . Returns ( Task . CompletedTask ) ;
119+ _mockStream . SetupSequence ( stream => stream . MoveNextAsync ( ) )
120+ . Returns ( new ValueTask < bool > ( true ) )
121+ . Returns ( ( ) =>
122+ {
123+ taskNextComplete . SetResult ( ) ;
124+ return new ValueTask < bool > ( taskSource . Task ) ;
125+ } ) ;
126+ _mockStream . Setup ( stream => stream . Current )
127+ . Returns ( new StreamWriteMessage . Types . FromServer
128+ {
129+ Status = StatusIds . Types . StatusCode . BadSession ,
130+ Issues = { new IssueMessage { Message = "Some message" } }
131+ } ) ;
132+
133+ using var writer = new WriterBuilder < long > ( _mockIDriver . Object , new WriterConfig ( "/topic" )
134+ { ProducerId = "producerId" } ) . Build ( ) ;
135+
136+ Assert . Equal ( "Initialization failed: Status: BadSession, Issues:\n [0] Fatal: Some message\n " ,
137+ ( await Assert . ThrowsAsync < WriterException > ( ( ) => writer . WriteAsync ( 123L ) ) ) . Message ) ;
138+
139+ await taskNextComplete . Task ;
140+ // check attempt repeated!!!
141+ _mockStream . Verify ( stream => stream . Write ( It . IsAny < StreamWriteMessage . Types . FromClient > ( ) ) , Times . Exactly ( 2 ) ) ;
142+ _mockStream . Verify ( stream => stream . MoveNextAsync ( ) , Times . Exactly ( 2 ) ) ;
143+ }
144+
145+ [ Fact ]
146+ public async Task Initialize_WhenInitResponseIsSchemaError_ThrowWriterExceptionOnWriteAsyncAndStopInitializing ( )
147+ {
148+ _mockStream . Setup ( stream => stream . Write ( It . IsAny < StreamWriteMessage . Types . FromClient > ( ) ) )
149+ . Returns ( Task . CompletedTask ) ;
150+ _mockStream . Setup ( stream => stream . MoveNextAsync ( ) )
151+ . Returns ( new ValueTask < bool > ( true ) ) ;
152+ _mockStream . Setup ( stream => stream . Current )
153+ . Returns ( new StreamWriteMessage . Types . FromServer
154+ {
155+ Status = StatusIds . Types . StatusCode . SchemeError ,
156+ Issues = { new IssueMessage { Message = "Topic not found" } }
157+ } ) ;
158+
159+ using var writer = new WriterBuilder < long > ( _mockIDriver . Object , new WriterConfig ( "/topic" )
160+ { ProducerId = "producerId" } ) . Build ( ) ;
161+
162+ Assert . Equal ( "Initialization failed: Status: SchemeError, Issues:\n [0] Fatal: Topic not found\n " ,
163+ ( await Assert . ThrowsAsync < WriterException > ( ( ) => writer . WriteAsync ( 123L ) ) ) . Message ) ;
164+
165+ // check not attempt repeated!!!
166+ _mockStream . Verify ( stream => stream . Write ( It . IsAny < StreamWriteMessage . Types . FromClient > ( ) ) , Times . Once ) ;
167+ _mockStream . Verify ( stream => stream . MoveNextAsync ( ) , Times . Once ) ;
168+ }
169+
170+ [ Fact ]
171+ public async Task Initialize_WhenNotSupportedCodec_ThrowWriterExceptionOnWriteAsyncAndStopInitializing ( )
172+ {
173+ _mockStream . Setup ( stream => stream . Write ( It . IsAny < StreamWriteMessage . Types . FromClient > ( ) ) )
174+ . Returns ( Task . CompletedTask ) ;
175+ _mockStream . Setup ( stream => stream . MoveNextAsync ( ) )
176+ . Returns ( new ValueTask < bool > ( true ) ) ;
177+ _mockStream . Setup ( stream => stream . Current )
178+ . Returns ( new StreamWriteMessage . Types . FromServer
179+ {
180+ InitResponse = new StreamWriteMessage . Types . InitResponse
181+ {
182+ LastSeqNo = 1 , PartitionId = 1 , SessionId = "SessionId" ,
183+ SupportedCodecs = new SupportedCodecs { Codecs = { 2 /* Gzip */ , 3 /* Lzop */ } }
184+ } ,
185+ Status = StatusIds . Types . StatusCode . Success ,
186+ } ) ;
187+
188+ using var writer = new WriterBuilder < long > ( _mockIDriver . Object , new WriterConfig ( "/topic" )
189+ { ProducerId = "producerId" , Codec = Codec . Raw } ) . Build ( ) ;
190+
191+ Assert . Equal ( "Topic[Path=\" /topic\" ] is not supported codec: Raw" ,
192+ ( await Assert . ThrowsAsync < WriterException > ( ( ) => writer . WriteAsync ( 123L ) ) ) . Message ) ;
193+
194+ // check not attempt repeated!!!
195+ _mockStream . Verify ( stream => stream . Write ( It . IsAny < StreamWriteMessage . Types . FromClient > ( ) ) , Times . Once ) ;
196+ _mockStream . Verify ( stream => stream . MoveNextAsync ( ) , Times . Once ) ;
197+ }
198+
199+
200+
201+ /*
202+ * _mockStream.Setup(stream => stream.Current)
203+ .Returns(new StreamWriteMessage.Types.FromServer
204+ {
205+ InitResponse = new StreamWriteMessage.Types.InitResponse
206+ { LastSeqNo = 1, PartitionId = 1, SessionId = "SessionId" },
207+ Status = StatusIds.Types.StatusCode.Success,
208+ });
209+ moveNextTry.SetResult(true);
210+ await Task.Yield();
211+
212+ var writeTask = writer.WriteAsync(100);
213+ moveNextTryWriteAck.SetResult(true);
214+
215+ _mockStream.Setup(stream => stream.Current).Returns(
216+ new StreamWriteMessage.Types.FromServer
217+ {
218+ WriteResponse = new StreamWriteMessage.Types.WriteResponse
219+ {
220+ Acks =
221+ {
222+ new StreamWriteMessage.Types.WriteResponse.Types.WriteAck
223+ {
224+ SeqNo = 1, Written =
225+ new StreamWriteMessage.Types.WriteResponse.Types.WriteAck.Types.Written
226+ { Offset = 2 }
227+ }
228+ }
229+ },
230+ Status = StatusIds.Types.StatusCode.Success
231+ });
232+ _mockStream.Setup(stream => stream.MoveNextAsync()).ReturnsAsync(true);
233+
234+ var writeResult = await writeTask;
235+ Assert.Equal(PersistenceStatus.Written, writeResult.Status);
236+ Assert.True(writeResult.TryGetOffset(out var offset));
237+ Assert.Equal(2, offset);
238+ _mockStream.Setup(stream => stream.MoveNextAsync()).ReturnsAsync(false);
239+ */
43240}
0 commit comments