| 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 |