[test][audio] test for simpleaudio lifecycle
Test to catch errors in ddk lifecycle for
SimpleAudioStream library. Test in response
to regression in ZX-3918.
Change-Id: I97db05114f3d22a31e0e59ce1ea456efe44b006a
diff --git a/zircon/system/dev/audio/lib/simple-audio-stream/BUILD.gn b/zircon/system/dev/audio/lib/simple-audio-stream/BUILD.gn
index fef9431..038a34d 100644
--- a/zircon/system/dev/audio/lib/simple-audio-stream/BUILD.gn
+++ b/zircon/system/dev/audio/lib/simple-audio-stream/BUILD.gn
@@ -26,3 +26,21 @@
"$zx/system/ulib/zx",
]
}
+
+test("sa-unittest") {
+ sources = [
+ "tests/sas-test.cpp",
+ ]
+ deps = [
+ ":simple-audio-stream",
+ "$zx/system/dev/lib/fake_ddk",
+ "$zx/system/dev/lib/operation",
+ "$zx/system/ulib/audio-driver-proto",
+ "$zx/system/ulib/audio-proto-utils",
+ "$zx/system/ulib/ddk",
+ "$zx/system/ulib/ddktl",
+ "$zx/system/ulib/fzl",
+ "$zx/system/ulib/sync",
+ "$zx/system/ulib/unittest",
+ ]
+}
diff --git a/zircon/system/dev/audio/lib/simple-audio-stream/tests/sas-test.cpp b/zircon/system/dev/audio/lib/simple-audio-stream/tests/sas-test.cpp
new file mode 100644
index 0000000..b4c061f
--- /dev/null
+++ b/zircon/system/dev/audio/lib/simple-audio-stream/tests/sas-test.cpp
@@ -0,0 +1,151 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <lib/fake_ddk/fake_ddk.h>
+#include <lib/simple-audio-stream/simple-audio-stream.h>
+#include <unittest/unittest.h>
+
+namespace audio {
+
+class MockSimpleAudio : public SimpleAudioStream {
+
+public:
+ MockSimpleAudio(zx_device_t* parent)
+ : SimpleAudioStream(parent, true /* is input */) {}
+
+protected:
+ zx_status_t Init() __TA_REQUIRES(domain_->token()) override {
+
+ fbl::AllocChecker ac;
+ supported_formats_.reserve(1, &ac);
+ if (!ac.check()) {
+ return ZX_ERR_NO_MEMORY;
+ }
+ audio_stream_format_range_t range;
+
+ range.min_channels = 2;
+ range.max_channels = 2;
+ range.sample_formats = AUDIO_SAMPLE_FORMAT_16BIT;
+ range.min_frames_per_second = 48000;
+ range.max_frames_per_second = 48000;
+ range.flags = ASF_RANGE_FLAG_FPS_48000_FAMILY;
+
+ supported_formats_.push_back(range);
+
+ // Set our gain capabilities.
+ cur_gain_state_.cur_gain = 0;
+ cur_gain_state_.cur_mute = false;
+ cur_gain_state_.cur_agc = false;
+ cur_gain_state_.min_gain = 0;
+ cur_gain_state_.max_gain = 0;
+ cur_gain_state_.gain_step = 0;
+ cur_gain_state_.can_mute = false;
+ cur_gain_state_.can_agc = false;
+
+ snprintf(device_name_, sizeof(device_name_), "test-audio-in");
+ snprintf(mfr_name_, sizeof(mfr_name_), "Bike Sheds, Inc.");
+ snprintf(prod_name_, sizeof(prod_name_), "testy_mctestface");
+
+ unique_id_ = AUDIO_STREAM_UNIQUE_ID_BUILTIN_MICROPHONE;
+
+ return ZX_OK;
+ }
+
+ zx_status_t ChangeFormat(const audio_proto::StreamSetFmtReq& req)
+ __TA_REQUIRES(domain_->token()) override {
+
+ return ZX_OK;
+ }
+
+ zx_status_t GetBuffer(const audio_proto::RingBufGetBufferReq& req,
+ uint32_t* out_num_rb_frames,
+ zx::vmo* out_buffer) __TA_REQUIRES(domain_->token()) override {
+ return ZX_OK;
+ }
+
+ zx_status_t Start(uint64_t* out_start_time) __TA_REQUIRES(domain_->token()) override {
+ *out_start_time = zx_clock_get_monotonic();
+ return ZX_OK;
+ }
+
+ zx_status_t Stop() __TA_REQUIRES(domain_->token()) override {
+ return ZX_OK;
+ }
+
+ void ShutdownHook() __TA_REQUIRES(domain_->token()) override {
+ Stop();
+ }
+};
+
+class Bind;
+class Bind : public fake_ddk::Bind {
+public:
+ int total_children() const { return total_children_; }
+
+ zx_status_t DeviceAdd(zx_driver_t* drv, zx_device_t* parent, device_add_args_t* args,
+ zx_device_t** out) override {
+ if (parent == fake_ddk::kFakeParent) {
+ *out = fake_ddk::kFakeDevice;
+ add_called_ = true;
+ } else if (parent == fake_ddk::kFakeDevice) {
+ *out = kFakeChild;
+ children_++;
+ total_children_++;
+ } else {
+ *out = kUnknownDevice;
+ bad_parent_ = false;
+ }
+ return ZX_OK;
+ }
+
+ zx_status_t DeviceRemove(zx_device_t* device) override {
+ if (device == fake_ddk::kFakeDevice) {
+ remove_called_ = true;
+ } else if (device == kFakeChild) {
+ // Check that all children are removed before the parent is removed.
+ if (!remove_called_) {
+ children_--;
+ }
+ } else {
+ bad_device_ = true;
+ }
+ return ZX_OK;
+ }
+
+ bool IsRemoved() { return remove_called_; }
+
+ bool Ok() {
+ return ((children_ == 0) && add_called_ && remove_called_ &&
+ !bad_parent_ && !bad_device_);
+ }
+private:
+ zx_device_t* kFakeChild = reinterpret_cast<zx_device_t*>(0x1234);
+ zx_device_t* kUnknownDevice = reinterpret_cast<zx_device_t*>(0x5678);
+
+ int total_children_ = 0;
+ int children_ = 0;
+
+ bool bad_parent_ = false;
+ bool bad_device_ = false;
+ bool add_called_ = false;
+ bool remove_called_ = false;
+};
+
+bool DdkLifeCycleTest() {
+ BEGIN_TEST;
+ Bind tester;
+ auto stream =
+ audio::SimpleAudioStream::Create<audio::MockSimpleAudio>(fake_ddk::kFakeParent);
+ ASSERT_NOT_NULL(stream);
+ ASSERT_EQ(ZX_OK, stream->DdkSuspend(0));
+ EXPECT_FALSE(tester.IsRemoved());
+ stream->DdkUnbind();
+ EXPECT_TRUE(tester.Ok());
+ END_TEST;
+}
+} //namespace audio
+
+BEGIN_TEST_CASE(SimpleAudioTest)
+RUN_TEST_SMALL(audio::DdkLifeCycleTest)
+END_TEST_CASE(SimpleAudioTest)
diff --git a/zircon/system/utest/BUILD.gn b/zircon/system/utest/BUILD.gn
index c9e142d..ca2b9b3 100644
--- a/zircon/system/utest/BUILD.gn
+++ b/zircon/system/utest/BUILD.gn
@@ -26,6 +26,7 @@
"$zx/system/core/netsvc:netsvc-test",
"$zx/system/core/svchost:crashsvc-test",
"$zx/system/core/virtcon:virtual-console-test",
+ "$zx/system/dev/audio/lib/simple-audio-stream:sa-unittest",
"$zx/system/dev/backlight/sg-micro:sgm37603a-test",
"$zx/system/dev/block/ahci:ahci-unittest",
"$zx/system/dev/block/ftl/test",