18bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 28bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 38bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// found in the LICENSE file. 48bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 58bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "content/test/mock_google_streaming_server.h" 68bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 78bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/bind.h" 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/numerics/safe_conversions.h" 98bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/strings/string_util.h" 108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/strings/utf_string_conversions.h" 118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/sys_byteorder.h" 128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "base/values.h" 138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "content/browser/speech/google_streaming_remote_engine.h" 148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "content/browser/speech/proto/google_streaming_api.pb.h" 158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "content/browser/speech/speech_recognition_manager_impl.h" 168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/base/escape.h" 178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/url_request/url_fetcher_delegate.h" 188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)#include "net/url_request/url_request_status.h" 198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)using base::HostToNet32; 215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)using base::checked_cast; 228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)namespace content { 248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)MockGoogleStreamingServer::MockGoogleStreamingServer(Delegate* delegate) 268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) : delegate_(delegate), 278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) kDownstreamUrlFetcherId( 288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) GoogleStreamingRemoteEngine::kDownstreamUrlFetcherIdForTesting), 298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) kUpstreamUrlFetcherId( 308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) GoogleStreamingRemoteEngine::kUpstreamUrlFetcherIdForTesting) { 318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) url_fetcher_factory_.SetDelegateForTests(this); 328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)MockGoogleStreamingServer::~MockGoogleStreamingServer() { 358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void MockGoogleStreamingServer::OnRequestStart(int fetcher_id) { 388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (fetcher_id != kDownstreamUrlFetcherId) 398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return; 408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Extract request argument from the the request URI. 428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) std::string query = GetURLFetcher(true)->GetOriginalURL().query(); 438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) std::vector<std::string> query_params; 448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) Tokenize(query, "&", &query_params); 458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const net::UnescapeRule::Type kUnescapeAll = 468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) net::UnescapeRule::NORMAL | 478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) net::UnescapeRule::SPACES | 488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) net::UnescapeRule::URL_SPECIAL_CHARS | 498bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) net::UnescapeRule::REPLACE_PLUS_WITH_SPACE; 508bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) for (size_t i = 0; i < query_params.size(); ++i) { 518bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const std::string query_param = query_params[i]; 528bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) std::vector<std::string> param_parts; 538bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) Tokenize(query_param, "=", ¶m_parts); 548bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (param_parts.size() != 2) 558bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) continue; 568bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) std::string param_key = net::UnescapeURLComponent(param_parts[0], 578bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) kUnescapeAll); 588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) std::string param_value = net::UnescapeURLComponent(param_parts[1], 598bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) kUnescapeAll); 608bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (param_key == "lang") { 618bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) request_language = param_value; 628bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } else if (param_key == "lm") { 638bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) request_grammar = param_value; 648bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 658bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 668bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 678bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) delegate_->OnClientConnected(); 688bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 698bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 708bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void MockGoogleStreamingServer::OnChunkUpload(int fetcher_id) { 718bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (fetcher_id != kUpstreamUrlFetcherId) 728bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return; 738bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) delegate_->OnClientAudioUpload(); 748bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (GetURLFetcher(false)->did_receive_last_chunk()) 758bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) delegate_->OnClientAudioUploadComplete(); 768bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 778bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void MockGoogleStreamingServer::OnRequestEnd(int fetcher_id) { 798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) if (fetcher_id != kDownstreamUrlFetcherId) 808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return; 818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) url_fetcher_factory_.RemoveFetcherFromMap(kDownstreamUrlFetcherId); 828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) delegate_->OnClientDisconnected(); 838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void MockGoogleStreamingServer::SimulateResult( 868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const SpeechRecognitionResult& result) { 878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) proto::SpeechRecognitionEvent proto_event; 888bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) proto_event.set_status(proto::SpeechRecognitionEvent::STATUS_SUCCESS); 898bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) proto::SpeechRecognitionResult* proto_result = proto_event.add_result(); 908bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) proto_result->set_final(!result.is_provisional); 918bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) for (size_t i = 0; i < result.hypotheses.size(); ++i) { 928bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) proto::SpeechRecognitionAlternative* proto_alternative = 938bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) proto_result->add_alternative(); 948bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) const SpeechRecognitionHypothesis& hypothesis = result.hypotheses[i]; 958bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) proto_alternative->set_confidence(hypothesis.confidence); 965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) proto_alternative->set_transcript(base::UTF16ToUTF8(hypothesis.utterance)); 978bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) } 988bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 998bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) std::string msg_string; 1008bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) proto_event.SerializeToString(&msg_string); 1018bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1028bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // Prepend 4 byte prefix length indication to the protobuf message as 1038bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) // envisaged by the google streaming recognition webservice protocol. 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) uint32 prefix = HostToNet32(checked_cast<uint32>(msg_string.size())); 1058bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) msg_string.insert(0, reinterpret_cast<char*>(&prefix), sizeof(prefix)); 1068bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1078bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) SimulateServerResponse(true, msg_string); 1088bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 1098bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1108bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void MockGoogleStreamingServer::SimulateServerFailure() { 1118bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) SimulateServerResponse(false, ""); 1128bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 1138bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1148bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void MockGoogleStreamingServer::SimulateMalformedResponse() { 1158bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) std::string json = 1168bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) "{\"status\":0,\"hypotheses\":""[{\"unknownkey\":\"hello\"}]}"; 1178bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) SimulateServerResponse(true, json); 1188bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 1198bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1208bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)const std::string& MockGoogleStreamingServer::GetRequestLanguage() const { 1218bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return request_language; 1228bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 1238bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1248bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)const std::string& MockGoogleStreamingServer::GetRequestGrammar() const { 1258bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return request_grammar; 1268bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 1278bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1288bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)void MockGoogleStreamingServer::SimulateServerResponse( 1298bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) bool success, const std::string& http_response) { 1308bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) net::TestURLFetcher* fetcher = GetURLFetcher(true); 1318bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1328bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) net::URLRequestStatus status; 1338bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) status.set_status(success ? net::URLRequestStatus::SUCCESS : 1348bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) net::URLRequestStatus::FAILED); 1358bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) fetcher->set_status(status); 1368bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) fetcher->set_response_code(success ? 200 : 500); 1378bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) fetcher->SetResponseString(http_response); 1388bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) fetcher->delegate()->OnURLFetchDownloadProgress(fetcher, 0, 0); 1398bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 1408bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1418bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)// Can return NULL if the SpeechRecognizer has not requested the connection yet. 1428bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)net::TestURLFetcher* MockGoogleStreamingServer::GetURLFetcher( 1438bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) bool downstream) const { 1448bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) return url_fetcher_factory_.GetFetcherByID( 1458bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) downstream ? kDownstreamUrlFetcherId : kUpstreamUrlFetcherId); 1468bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} 1478bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles) 1488bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)} // namespace content 149