Skip to content
This repository has been archived by the owner on Jan 16, 2024. It is now read-only.

Commit

Permalink
Version 1.25.0 alexa-client-sdk
Browse files Browse the repository at this point in the history
Changes in this update:

Feature enhancements, updates, and resolved issues from all releases are available on the [Amazon developer portal](https://developer.amazon.com/docs/alexa/avs-device-sdk/release-notes.html)
  • Loading branch information
womw committed Aug 24, 2021
1 parent e40477e commit f0c606d
Show file tree
Hide file tree
Showing 200 changed files with 7,745 additions and 2,560 deletions.
17 changes: 17 additions & 0 deletions ACL/include/ACL/Transport/MessageRequestHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,17 @@ class MessageRequestHandler
*/
void reportMessageRequestFinished();

/**
* Record a stream metric once when a specific threshold of bytes have been read from the stream.
* The stream metric name and threshold will be specified in the MessageRequest.
*/
void recordStreamMetric(int bytes);

/**
* Record the metric that specifics the start of sending the Message Event to the cloud.
*/
void recordStartOfEventMetric();

/// The MessageRequest that this handler is servicing.
std::shared_ptr<avsCommon::avs::MessageRequest> m_messageRequest;

Expand Down Expand Up @@ -146,6 +157,12 @@ class MessageRequestHandler

/// Status to be reported back to the @c MessageRequest.
avsCommon::sdkInterfaces::MessageRequestObserverInterface::Status m_resultStatus;

/// The number of bytes that have been read from the stream.
unsigned int m_streamBytesRead;

/// If the stream metric has already been recorded.
bool m_recordedStreamMetric;
};

} // namespace acl
Expand Down
2 changes: 2 additions & 0 deletions ACL/src/Transport/HTTP2Transport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,8 @@ void HTTP2Transport::onAuthStateChange(
ACSDK_ERROR(LX_P("shuttingDown").d("reason", "unrecoverableAuthError"));
setStateLocked(State::SHUTDOWN, ConnectionStatusObserverInterface::ChangedReason::UNRECOVERABLE_ERROR);
return;
case AuthObserverInterface::State::AUTHORIZING:
return;
}

ACSDK_ERROR(LX_P("shuttingDown").d("reason", "unknownAuthStatus").d("newState", static_cast<int>(newState)));
Expand Down
56 changes: 55 additions & 1 deletion ACL/src/Transport/MessageRequestHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ static const std::string ACL_METRIC_SOURCE_PREFIX = "ACL-";
/// Metric identifier for send mime data error
static const std::string SEND_DATA_ERROR = "ERROR.SEND_DATA_ERROR";

/// Metric identifier for start of Mime data event being sent to the cloud.
static const std::string START_EVENT_SENT_TO_CLOUD = "START_EVENT_SENT_TO_CLOUD";

/// Read status tag
static const std::string READ_STATUS_TAG = "READ_STATUS";

Expand Down Expand Up @@ -165,6 +168,53 @@ static void submitMessageSendErrorMetric(
recordMetric(metricRecorder, metricEvent);
}

void MessageRequestHandler::recordStreamMetric(int bytes) {
if (m_messageRequest == nullptr) {
return;
}

if (m_metricRecorder == nullptr) {
return;
}
if (m_recordedStreamMetric) {
return;
}
m_streamBytesRead += bytes;
std::string metricName{m_messageRequest->getStreamMetricName()};
auto threshold = m_messageRequest->getStreamBytesThreshold();
if (metricName == "" || threshold == 0) {
return;
}
if (threshold <= m_streamBytesRead) {
auto metricEvent = MetricEventBuilder{}
.setActivityName(ACL_METRIC_SOURCE_PREFIX + metricName)
.addDataPoint(DataPointCounterBuilder{}.setName(metricName).increment(1).build())
.build();
if (!metricEvent) {
ACSDK_ERROR(LX("recordStreamMetric").m("submitMetricFailed").d("reason", "invalid metric event"));
return;
}
recordMetric(m_metricRecorder, metricEvent);
m_recordedStreamMetric = true;
}
}

void MessageRequestHandler::recordStartOfEventMetric() {
if (!m_metricRecorder) {
return;
}
auto metricEvent =
MetricEventBuilder{}
.setActivityName(ACL_METRIC_SOURCE_PREFIX + START_EVENT_SENT_TO_CLOUD)
.addDataPoint(DataPointCounterBuilder{}.setName(START_EVENT_SENT_TO_CLOUD).increment(1).build())
.build();
if (!metricEvent) {
ACSDK_ERROR(LX("recordStartOfEventMetric").m("submitMetricFailed").d("reason", "invalid metric event"));
return;
}
recordMetric(m_metricRecorder, metricEvent);
}

MessageRequestHandler::~MessageRequestHandler() {
reportMessageRequestAcknowledged();
reportMessageRequestFinished();
Expand Down Expand Up @@ -250,7 +300,9 @@ MessageRequestHandler::MessageRequestHandler(
m_wasMessageRequestFinishedReported{false},
m_responseCode{0},
m_powerResource{powerResource},
m_resultStatus{MessageRequestObserverInterface::Status::PENDING} {
m_resultStatus{MessageRequestObserverInterface::Status::PENDING},
m_streamBytesRead{0},
m_recordedStreamMetric{false} {
ACSDK_DEBUG7(LX(__func__).d("context", context.get()).d("messageRequest", messageRequest.get()));

if (m_powerResource) {
Expand Down Expand Up @@ -321,6 +373,7 @@ HTTP2SendDataResult MessageRequestHandler::onSendMimePartData(char* bytes, size_
std::copy(m_jsonNext, m_jsonNext + countToCopy, bytes);
m_jsonNext += countToCopy;
m_countOfJsonBytesLeft -= countToCopy;
recordStartOfEventMetric();
return HTTP2SendDataResult(countToCopy);
} else {
m_countOfPartsSent++;
Expand All @@ -329,6 +382,7 @@ HTTP2SendDataResult MessageRequestHandler::onSendMimePartData(char* bytes, size_
} else if (m_namedReader) {
auto readStatus = AttachmentReader::ReadStatus::OK;
auto bytesRead = m_namedReader->reader->read(bytes, size, &readStatus);
recordStreamMetric(bytesRead);
ACSDK_DEBUG9(LX("attachmentRead").d("readStatus", (int)readStatus).d("bytesRead", bytesRead));
switch (readStatus) {
// The good cases.
Expand Down
4 changes: 1 addition & 3 deletions ACL/src/Transport/MessageRouter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,17 +121,15 @@ void MessageRouter::enable() {

void MessageRouter::doShutdown() {
disable();

// The above call will release all the transports. If m_requestQueue is non-empty once all of the transports
// have been released, any outstanding MessageRequest instances must receive an onCompleted(NOT_CONNECTED)
// notification.
std::unique_lock<std::mutex> lock{m_connectionMutex};
if (!m_requestQueue->empty()) {
while (!m_requestQueue->empty()) {
auto request = m_requestQueue->dequeueOldestRequest();
if (request != nullptr) {
request->sendCompleted(MessageRequestObserverInterface::Status::NOT_CONNECTED);
}
m_requestQueue->clear();
}
lock.unlock();

Expand Down
1 change: 1 addition & 0 deletions ACL/test/Transport/Common/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ if (BUILD_TESTING)
add_library(ACLTransportCommonTestLib
MockHTTP2Connection.cpp
MockHTTP2Request.cpp
TestMessageRequestObserver.cpp
MockMimeResponseSink.cpp)
target_include_directories(ACLTransportCommonTestLib PUBLIC
"${ACL_SOURCE_DIR}/include"
Expand Down
36 changes: 36 additions & 0 deletions ACL/test/Transport/Common/TestMessageRequestObserver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0/
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/

#include "TestMessageRequestObserver.h"

namespace alexaClientSDK {
namespace avsCommon {
namespace utils {
namespace observer {
namespace test {

void TestMessageRequestObserver::onSendCompleted(MessageRequestObserverInterface::Status status) {
m_status.setValue(status);
}

void TestMessageRequestObserver::onExceptionReceived(const std::string& exceptionMessage) {
m_exception.setValue(exceptionMessage);
}

} // namespace test
} // namespace observer
} // namespace utils
} // namespace avsCommon
} // namespace alexaClientSDK
30 changes: 2 additions & 28 deletions ACL/test/Transport/HTTP2TransportTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "MockPostConnect.h"
#include "MockPostConnectFactory.h"
#include "MockTransportObserver.h"
#include "TestMessageRequestObserver.h"

#include "ACL/Transport/SynchronizedMessageRequestQueue.h"

Expand All @@ -56,6 +57,7 @@ using namespace avsCommon::utils::http;
using namespace avsCommon::utils::http2;
using namespace avsCommon::utils::http2::test;
using namespace avsCommon::utils::metrics::test;
using namespace avsCommon::utils::observer::test;
using namespace ::testing;

/// Test AVS Gateway.
Expand Down Expand Up @@ -229,34 +231,6 @@ class HTTP2TransportTest : public Test {
PromiseFuturePair<void> m_transportConnected;
};

/**
* A @c MessageRequestObserverInterface implementation used in this test.
*/
class TestMessageRequestObserver : public avsCommon::sdkInterfaces::MessageRequestObserverInterface {
public:
/*
* Called when a message request has been processed by AVS.
*/
void onSendCompleted(MessageRequestObserverInterface::Status status) {
m_status.setValue(status);
}

/*
* Called when an exception is thrown when trying to send a message to AVS.
*/
void onExceptionReceived(const std::string& exceptionMessage) {
m_exception.setValue(exceptionMessage);
}

/// A promise that @c MessageRequestObserverInterface::onSendCompleted() will be called with a @c
/// MessageRequestObserverInterface::Status value
PromiseFuturePair<MessageRequestObserverInterface::Status> m_status;

/// A promise that @c MessageRequestObserverInterface::onExceptionReceived() will be called with an exception
/// message
PromiseFuturePair<std::string> m_exception;
};

void HTTP2TransportTest::SetUp() {
m_mockAuthDelegate = std::make_shared<NiceMock<MockAuthDelegate>>();
m_mockHttp2Connection = std::make_shared<NiceMock<MockHTTP2Connection>>(FULL_DOWNCHANNEL_URL, FULL_PING_URL);
Expand Down
34 changes: 30 additions & 4 deletions ACL/test/Transport/MessageRouterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
*/

#include "MessageRouterTest.h"

#include <gtest/gtest.h>

namespace alexaClientSDK {
Expand Down Expand Up @@ -150,12 +149,39 @@ TEST_F(MessageRouterTest, test_sendMessageDoesNotSendAfterDisconnected) {
m_router->sendMessage(messageRequest);
}

TEST_F(MessageRouterTest, test_disconnectDisconnectsConnectedTransports) {
TEST_F(MessageRouterTest, test_shutdownCalledWithMultipleMessages) {
setupStateToConnected();

EXPECT_CALL(*m_mockTransport, doShutdown()).Times(1);
// wait for the result to propagate by scheduling a task on the client executor
waitOnMessageRouter(SHORT_TIMEOUT_MS);

m_router->disable();
ASSERT_EQ(
m_mockMessageRouterObserver->getLatestConnectionStatus(), ConnectionStatusObserverInterface::Status::CONNECTED);

auto firstRequest = createMessageRequest();
auto otherRequest = createMessageRequest();

auto firstObserver = createObserver();
auto otherObserver = createObserver();

firstRequest->addObserver(firstObserver);
otherRequest->addObserver(otherObserver);

m_router->sendMessage(firstRequest);
m_router->sendMessage(otherRequest);

m_router->shutdown();

ASSERT_EQ(
m_mockMessageRouterObserver->getLatestConnectionStatus(),
ConnectionStatusObserverInterface::Status::DISCONNECTED);

ASSERT_EQ(
m_mockMessageRouterObserver->getLatestConnectionChangedReason(),
ConnectionStatusObserverInterface::ChangedReason::ACL_CLIENT_REQUEST);

ASSERT_EQ(firstObserver->m_status.getValue(), MessageRequestObserverInterface::Status::NOT_CONNECTED);
ASSERT_EQ(otherObserver->m_status.getValue(), MessageRequestObserverInterface::Status::NOT_CONNECTED);
}

TEST_F(MessageRouterTest, test_serverSideDisconnectWithLongDelayedReconnectReportsPending) {
Expand Down
22 changes: 19 additions & 3 deletions ACL/test/Transport/MessageRouterTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include "ACL/Transport/MessageRouter.h"
#include "ACL/Transport/MessageConsumerInterface.h"

#include "TestMessageRequestObserver.h"

namespace alexaClientSDK {
namespace acl {
namespace test {
Expand All @@ -40,6 +42,9 @@ using namespace transport::test;
using namespace avsCommon::avs::attachment;
using namespace avsCommon::utils::threading;
using namespace avsCommon::utils::memory;
using namespace alexaClientSDK::avsCommon::sdkInterfaces;
using namespace avsCommon::utils;
using namespace avsCommon::utils::observer::test;

using namespace ::testing;

Expand Down Expand Up @@ -71,6 +76,10 @@ class TestableMessageRouter : public MessageRouter {
return status == std::future_status::ready;
}

bool isExecutorActive() {
return !m_executor.isShutdown();
}

/// Short amount of time to allow for an automatic reconnect before notifying of a server side disconnect.
static const std::chrono::milliseconds SHORT_SERVER_SIDE_DISCONNECT_GRACE_PERIOD;
};
Expand Down Expand Up @@ -117,18 +126,25 @@ class MessageRouterTest : public ::testing::Test {
}

void TearDown() {
// Wait on MessageRouter to ensure everything is finished
waitOnMessageRouter(SHORT_TIMEOUT_MS);
if (m_router->isExecutorActive()) {
// Wait on MessageRouter to ensure everything is finished
waitOnMessageRouter(SHORT_TIMEOUT_MS);
}
}

std::shared_ptr<avsCommon::avs::MessageRequest> createMessageRequest() {
return std::make_shared<avsCommon::avs::MessageRequest>(MESSAGE);
}

std::shared_ptr<TestMessageRequestObserver> createObserver() {
return std::make_shared<TestMessageRequestObserver>();
}

void waitOnMessageRouter(std::chrono::milliseconds millisecondsToWait) {
auto status = m_router->isExecutorReady(millisecondsToWait);

ASSERT_EQ(true, status);
}

void setupStateToPending() {
initializeMockTransport(m_mockTransport.get());
m_router->enable();
Expand Down

0 comments on commit f0c606d

Please sign in to comment.