OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <queue> | 5 #include <queue> |
6 | 6 |
7 #include "base/memory/scoped_ptr.h" | 7 #include "base/memory/scoped_ptr.h" |
8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
9 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
10 #include "content/browser/speech/audio_buffer.h" | 10 #include "content/browser/speech/audio_buffer.h" |
11 #include "content/browser/speech/google_streaming_remote_engine.h" | 11 #include "content/browser/speech/google_streaming_remote_engine.h" |
12 #include "content/browser/speech/proto/google_streaming_api.pb.h" | 12 #include "content/browser/speech/proto/google_streaming_api.pb.h" |
13 #include "content/public/common/speech_recognition_error.h" | 13 #include "content/public/common/speech_recognition_error.h" |
14 #include "content/public/common/speech_recognition_result.h" | 14 #include "content/public/common/speech_recognition_result.h" |
15 #include "net/url_request/test_url_fetcher_factory.h" | 15 #include "net/url_request/test_url_fetcher_factory.h" |
16 #include "net/url_request/url_request_context_getter.h" | 16 #include "net/url_request/url_request_context_getter.h" |
17 #include "net/url_request/url_request_status.h" | 17 #include "net/url_request/url_request_status.h" |
18 #include "testing/gtest/include/gtest/gtest.h" | 18 #include "testing/gtest/include/gtest/gtest.h" |
19 | 19 |
20 using content::SpeechRecognitionHypothesis; | |
21 using content::SpeechRecognitionResult; | |
22 using net::URLRequestStatus; | 20 using net::URLRequestStatus; |
23 using net::TestURLFetcher; | 21 using net::TestURLFetcher; |
24 using net::TestURLFetcherFactory; | 22 using net::TestURLFetcherFactory; |
25 | 23 |
26 namespace speech { | 24 namespace content { |
27 | 25 |
28 // Note: the terms upstream and downstream are from the point-of-view of the | 26 // Note: the terms upstream and downstream are from the point-of-view of the |
29 // client (engine_under_test_). | 27 // client (engine_under_test_). |
30 | 28 |
31 class GoogleStreamingRemoteEngineTest | 29 class GoogleStreamingRemoteEngineTest : public SpeechRecognitionEngineDelegate, |
32 : public SpeechRecognitionEngineDelegate, | 30 public testing::Test { |
33 public testing::Test { | |
34 public: | 31 public: |
35 GoogleStreamingRemoteEngineTest() | 32 GoogleStreamingRemoteEngineTest() |
36 : last_number_of_upstream_chunks_seen_(0U), | 33 : last_number_of_upstream_chunks_seen_(0U), |
37 error_(content::SPEECH_RECOGNITION_ERROR_NONE) { } | 34 error_(SPEECH_RECOGNITION_ERROR_NONE) { } |
38 | 35 |
39 // Creates a speech recognition request and invokes its URL fetcher delegate | 36 // Creates a speech recognition request and invokes its URL fetcher delegate |
40 // with the given test data. | 37 // with the given test data. |
41 void CreateAndTestRequest(bool success, const std::string& http_response); | 38 void CreateAndTestRequest(bool success, const std::string& http_response); |
42 | 39 |
43 // SpeechRecognitionRequestDelegate methods. | 40 // SpeechRecognitionRequestDelegate methods. |
44 virtual void OnSpeechRecognitionEngineResult( | 41 virtual void OnSpeechRecognitionEngineResult( |
45 const SpeechRecognitionResult& result) OVERRIDE { | 42 const SpeechRecognitionResult& result) OVERRIDE { |
46 results_.push(result); | 43 results_.push(result); |
47 } | 44 } |
48 virtual void OnSpeechRecognitionEngineError( | 45 virtual void OnSpeechRecognitionEngineError( |
49 const content::SpeechRecognitionError& error) OVERRIDE { | 46 const SpeechRecognitionError& error) OVERRIDE { |
50 error_ = error.code; | 47 error_ = error.code; |
51 } | 48 } |
52 | 49 |
53 // testing::Test methods. | 50 // testing::Test methods. |
54 virtual void SetUp() OVERRIDE; | 51 virtual void SetUp() OVERRIDE; |
55 virtual void TearDown() OVERRIDE; | 52 virtual void TearDown() OVERRIDE; |
56 | 53 |
57 protected: | 54 protected: |
58 enum DownstreamError { | 55 enum DownstreamError { |
59 DOWNSTREAM_ERROR_NONE, | 56 DOWNSTREAM_ERROR_NONE, |
(...skipping 17 matching lines...) Expand all Loading... |
77 const proto::SpeechRecognitionEvent& result); | 74 const proto::SpeechRecognitionEvent& result); |
78 void ProvideMockResultDownstream(const SpeechRecognitionResult& result); | 75 void ProvideMockResultDownstream(const SpeechRecognitionResult& result); |
79 void ExpectResultReceived(const SpeechRecognitionResult& result); | 76 void ExpectResultReceived(const SpeechRecognitionResult& result); |
80 void CloseMockDownstream(DownstreamError error); | 77 void CloseMockDownstream(DownstreamError error); |
81 | 78 |
82 scoped_ptr<GoogleStreamingRemoteEngine> engine_under_test_; | 79 scoped_ptr<GoogleStreamingRemoteEngine> engine_under_test_; |
83 TestURLFetcherFactory url_fetcher_factory_; | 80 TestURLFetcherFactory url_fetcher_factory_; |
84 size_t last_number_of_upstream_chunks_seen_; | 81 size_t last_number_of_upstream_chunks_seen_; |
85 MessageLoop message_loop_; | 82 MessageLoop message_loop_; |
86 std::string response_buffer_; | 83 std::string response_buffer_; |
87 content::SpeechRecognitionErrorCode error_; | 84 SpeechRecognitionErrorCode error_; |
88 std::queue<SpeechRecognitionResult> results_; | 85 std::queue<SpeechRecognitionResult> results_; |
89 }; | 86 }; |
90 | 87 |
91 TEST_F(GoogleStreamingRemoteEngineTest, SingleDefinitiveResult) { | 88 TEST_F(GoogleStreamingRemoteEngineTest, SingleDefinitiveResult) { |
92 StartMockRecognition(); | 89 StartMockRecognition(); |
93 ASSERT_TRUE(GetUpstreamFetcher()); | 90 ASSERT_TRUE(GetUpstreamFetcher()); |
94 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall()); | 91 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall()); |
95 | 92 |
96 // Inject some dummy audio chunks and check a corresponding chunked upload | 93 // Inject some dummy audio chunks and check a corresponding chunked upload |
97 // is performed every time on the server. | 94 // is performed every time on the server. |
(...skipping 17 matching lines...) Expand all Loading... |
115 SpeechRecognitionHypothesis(UTF8ToUTF16("hypothesis 2"), 0.2F)); | 112 SpeechRecognitionHypothesis(UTF8ToUTF16("hypothesis 2"), 0.2F)); |
116 | 113 |
117 ProvideMockResultDownstream(result); | 114 ProvideMockResultDownstream(result); |
118 ExpectResultReceived(result); | 115 ExpectResultReceived(result); |
119 ASSERT_TRUE(engine_under_test_->IsRecognitionPending()); | 116 ASSERT_TRUE(engine_under_test_->IsRecognitionPending()); |
120 | 117 |
121 // Ensure everything is closed cleanly after the downstream is closed. | 118 // Ensure everything is closed cleanly after the downstream is closed. |
122 CloseMockDownstream(DOWNSTREAM_ERROR_NONE); | 119 CloseMockDownstream(DOWNSTREAM_ERROR_NONE); |
123 ASSERT_FALSE(engine_under_test_->IsRecognitionPending()); | 120 ASSERT_FALSE(engine_under_test_->IsRecognitionPending()); |
124 EndMockRecognition(); | 121 EndMockRecognition(); |
125 ASSERT_EQ(content::SPEECH_RECOGNITION_ERROR_NONE, error_); | 122 ASSERT_EQ(SPEECH_RECOGNITION_ERROR_NONE, error_); |
126 ASSERT_EQ(0U, results_.size()); | 123 ASSERT_EQ(0U, results_.size()); |
127 } | 124 } |
128 | 125 |
129 TEST_F(GoogleStreamingRemoteEngineTest, SeveralStreamingResults) { | 126 TEST_F(GoogleStreamingRemoteEngineTest, SeveralStreamingResults) { |
130 StartMockRecognition(); | 127 StartMockRecognition(); |
131 ASSERT_TRUE(GetUpstreamFetcher()); | 128 ASSERT_TRUE(GetUpstreamFetcher()); |
132 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall()); | 129 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall()); |
133 | 130 |
134 for (int i = 0; i < 4; ++i) { | 131 for (int i = 0; i < 4; ++i) { |
135 InjectDummyAudioChunk(); | 132 InjectDummyAudioChunk(); |
(...skipping 21 matching lines...) Expand all Loading... |
157 result.hypotheses.push_back( | 154 result.hypotheses.push_back( |
158 SpeechRecognitionHypothesis(UTF8ToUTF16("The final result"), 1.0F)); | 155 SpeechRecognitionHypothesis(UTF8ToUTF16("The final result"), 1.0F)); |
159 ProvideMockResultDownstream(result); | 156 ProvideMockResultDownstream(result); |
160 ExpectResultReceived(result); | 157 ExpectResultReceived(result); |
161 ASSERT_TRUE(engine_under_test_->IsRecognitionPending()); | 158 ASSERT_TRUE(engine_under_test_->IsRecognitionPending()); |
162 | 159 |
163 // Ensure everything is closed cleanly after the downstream is closed. | 160 // Ensure everything is closed cleanly after the downstream is closed. |
164 CloseMockDownstream(DOWNSTREAM_ERROR_NONE); | 161 CloseMockDownstream(DOWNSTREAM_ERROR_NONE); |
165 ASSERT_FALSE(engine_under_test_->IsRecognitionPending()); | 162 ASSERT_FALSE(engine_under_test_->IsRecognitionPending()); |
166 EndMockRecognition(); | 163 EndMockRecognition(); |
167 ASSERT_EQ(content::SPEECH_RECOGNITION_ERROR_NONE, error_); | 164 ASSERT_EQ(SPEECH_RECOGNITION_ERROR_NONE, error_); |
168 ASSERT_EQ(0U, results_.size()); | 165 ASSERT_EQ(0U, results_.size()); |
169 } | 166 } |
170 | 167 |
171 TEST_F(GoogleStreamingRemoteEngineTest, NoFinalResultAfterAudioChunksEnded) { | 168 TEST_F(GoogleStreamingRemoteEngineTest, NoFinalResultAfterAudioChunksEnded) { |
172 StartMockRecognition(); | 169 StartMockRecognition(); |
173 ASSERT_TRUE(GetUpstreamFetcher()); | 170 ASSERT_TRUE(GetUpstreamFetcher()); |
174 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall()); | 171 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall()); |
175 | 172 |
176 // Simulate one pushed audio chunk. | 173 // Simulate one pushed audio chunk. |
177 InjectDummyAudioChunk(); | 174 InjectDummyAudioChunk(); |
(...skipping 14 matching lines...) Expand all Loading... |
192 CloseMockDownstream(DOWNSTREAM_ERROR_NONE); | 189 CloseMockDownstream(DOWNSTREAM_ERROR_NONE); |
193 | 190 |
194 // Expect an empty result, aimed at notifying recognition ended with no | 191 // Expect an empty result, aimed at notifying recognition ended with no |
195 // actual results nor errors. | 192 // actual results nor errors. |
196 SpeechRecognitionResult empty_result; | 193 SpeechRecognitionResult empty_result; |
197 ExpectResultReceived(empty_result); | 194 ExpectResultReceived(empty_result); |
198 | 195 |
199 // Ensure everything is closed cleanly after the downstream is closed. | 196 // Ensure everything is closed cleanly after the downstream is closed. |
200 ASSERT_FALSE(engine_under_test_->IsRecognitionPending()); | 197 ASSERT_FALSE(engine_under_test_->IsRecognitionPending()); |
201 EndMockRecognition(); | 198 EndMockRecognition(); |
202 ASSERT_EQ(content::SPEECH_RECOGNITION_ERROR_NONE, error_); | 199 ASSERT_EQ(SPEECH_RECOGNITION_ERROR_NONE, error_); |
203 ASSERT_EQ(0U, results_.size()); | 200 ASSERT_EQ(0U, results_.size()); |
204 } | 201 } |
205 | 202 |
206 TEST_F(GoogleStreamingRemoteEngineTest, NoMatchError) { | 203 TEST_F(GoogleStreamingRemoteEngineTest, NoMatchError) { |
207 StartMockRecognition(); | 204 StartMockRecognition(); |
208 ASSERT_TRUE(GetUpstreamFetcher()); | 205 ASSERT_TRUE(GetUpstreamFetcher()); |
209 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall()); | 206 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall()); |
210 | 207 |
211 for (int i = 0; i < 3; ++i) | 208 for (int i = 0; i < 3; ++i) |
212 InjectDummyAudioChunk(); | 209 InjectDummyAudioChunk(); |
(...skipping 26 matching lines...) Expand all Loading... |
239 | 236 |
240 InjectDummyAudioChunk(); | 237 InjectDummyAudioChunk(); |
241 ASSERT_EQ(1U, UpstreamChunksUploadedFromLastCall()); | 238 ASSERT_EQ(1U, UpstreamChunksUploadedFromLastCall()); |
242 | 239 |
243 // Close the downstream with a HTTP 500 error. | 240 // Close the downstream with a HTTP 500 error. |
244 CloseMockDownstream(DOWNSTREAM_ERROR_HTTP500); | 241 CloseMockDownstream(DOWNSTREAM_ERROR_HTTP500); |
245 | 242 |
246 // Expect a SPEECH_RECOGNITION_ERROR_NETWORK error to be raised. | 243 // Expect a SPEECH_RECOGNITION_ERROR_NETWORK error to be raised. |
247 ASSERT_FALSE(engine_under_test_->IsRecognitionPending()); | 244 ASSERT_FALSE(engine_under_test_->IsRecognitionPending()); |
248 EndMockRecognition(); | 245 EndMockRecognition(); |
249 ASSERT_EQ(content::SPEECH_RECOGNITION_ERROR_NETWORK, error_); | 246 ASSERT_EQ(SPEECH_RECOGNITION_ERROR_NETWORK, error_); |
250 ASSERT_EQ(0U, results_.size()); | 247 ASSERT_EQ(0U, results_.size()); |
251 } | 248 } |
252 | 249 |
253 TEST_F(GoogleStreamingRemoteEngineTest, NetworkError) { | 250 TEST_F(GoogleStreamingRemoteEngineTest, NetworkError) { |
254 StartMockRecognition(); | 251 StartMockRecognition(); |
255 ASSERT_TRUE(GetUpstreamFetcher()); | 252 ASSERT_TRUE(GetUpstreamFetcher()); |
256 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall()); | 253 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall()); |
257 | 254 |
258 InjectDummyAudioChunk(); | 255 InjectDummyAudioChunk(); |
259 ASSERT_EQ(1U, UpstreamChunksUploadedFromLastCall()); | 256 ASSERT_EQ(1U, UpstreamChunksUploadedFromLastCall()); |
260 | 257 |
261 // Close the downstream fetcher simulating a network failure. | 258 // Close the downstream fetcher simulating a network failure. |
262 CloseMockDownstream(DOWNSTREAM_ERROR_NETWORK); | 259 CloseMockDownstream(DOWNSTREAM_ERROR_NETWORK); |
263 | 260 |
264 // Expect a SPEECH_RECOGNITION_ERROR_NETWORK error to be raised. | 261 // Expect a SPEECH_RECOGNITION_ERROR_NETWORK error to be raised. |
265 ASSERT_FALSE(engine_under_test_->IsRecognitionPending()); | 262 ASSERT_FALSE(engine_under_test_->IsRecognitionPending()); |
266 EndMockRecognition(); | 263 EndMockRecognition(); |
267 ASSERT_EQ(content::SPEECH_RECOGNITION_ERROR_NETWORK, error_); | 264 ASSERT_EQ(SPEECH_RECOGNITION_ERROR_NETWORK, error_); |
268 ASSERT_EQ(0U, results_.size()); | 265 ASSERT_EQ(0U, results_.size()); |
269 } | 266 } |
270 | 267 |
271 TEST_F(GoogleStreamingRemoteEngineTest, Stability) { | 268 TEST_F(GoogleStreamingRemoteEngineTest, Stability) { |
272 StartMockRecognition(); | 269 StartMockRecognition(); |
273 ASSERT_TRUE(GetUpstreamFetcher()); | 270 ASSERT_TRUE(GetUpstreamFetcher()); |
274 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall()); | 271 ASSERT_EQ(0U, UpstreamChunksUploadedFromLastCall()); |
275 | 272 |
276 // Upload a dummy audio chunk. | 273 // Upload a dummy audio chunk. |
277 InjectDummyAudioChunk(); | 274 InjectDummyAudioChunk(); |
(...skipping 24 matching lines...) Expand all Loading... |
302 ASSERT_TRUE(engine_under_test_->IsRecognitionPending()); | 299 ASSERT_TRUE(engine_under_test_->IsRecognitionPending()); |
303 | 300 |
304 // Shut down. | 301 // Shut down. |
305 CloseMockDownstream(DOWNSTREAM_ERROR_NONE); | 302 CloseMockDownstream(DOWNSTREAM_ERROR_NONE); |
306 ASSERT_FALSE(engine_under_test_->IsRecognitionPending()); | 303 ASSERT_FALSE(engine_under_test_->IsRecognitionPending()); |
307 EndMockRecognition(); | 304 EndMockRecognition(); |
308 | 305 |
309 // Since there was no final result, we get an empty "no match" result. | 306 // Since there was no final result, we get an empty "no match" result. |
310 SpeechRecognitionResult empty_result; | 307 SpeechRecognitionResult empty_result; |
311 ExpectResultReceived(empty_result); | 308 ExpectResultReceived(empty_result); |
312 ASSERT_EQ(content::SPEECH_RECOGNITION_ERROR_NONE, error_); | 309 ASSERT_EQ(SPEECH_RECOGNITION_ERROR_NONE, error_); |
313 ASSERT_EQ(0U, results_.size()); | 310 ASSERT_EQ(0U, results_.size()); |
314 } | 311 } |
315 | 312 |
316 void GoogleStreamingRemoteEngineTest::SetUp() { | 313 void GoogleStreamingRemoteEngineTest::SetUp() { |
317 engine_under_test_.reset( | 314 engine_under_test_.reset( |
318 new GoogleStreamingRemoteEngine(NULL /*URLRequestContextGetter*/)); | 315 new GoogleStreamingRemoteEngine(NULL /*URLRequestContextGetter*/)); |
319 engine_under_test_->set_delegate(this); | 316 engine_under_test_->set_delegate(this); |
320 } | 317 } |
321 | 318 |
322 void GoogleStreamingRemoteEngineTest::TearDown() { | 319 void GoogleStreamingRemoteEngineTest::TearDown() { |
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
476 | 473 |
477 std::string GoogleStreamingRemoteEngineTest::ToBigEndian32(uint32 value) { | 474 std::string GoogleStreamingRemoteEngineTest::ToBigEndian32(uint32 value) { |
478 char raw_data[4]; | 475 char raw_data[4]; |
479 raw_data[0] = static_cast<uint8>((value >> 24) & 0xFF); | 476 raw_data[0] = static_cast<uint8>((value >> 24) & 0xFF); |
480 raw_data[1] = static_cast<uint8>((value >> 16) & 0xFF); | 477 raw_data[1] = static_cast<uint8>((value >> 16) & 0xFF); |
481 raw_data[2] = static_cast<uint8>((value >> 8) & 0xFF); | 478 raw_data[2] = static_cast<uint8>((value >> 8) & 0xFF); |
482 raw_data[3] = static_cast<uint8>(value & 0xFF); | 479 raw_data[3] = static_cast<uint8>(value & 0xFF); |
483 return std::string(raw_data, sizeof(raw_data)); | 480 return std::string(raw_data, sizeof(raw_data)); |
484 } | 481 } |
485 | 482 |
486 } // namespace speech | 483 } // namespace content |
OLD | NEW |