Home | History | Annotate | Download | only in functional
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #define LOG_TAG "tv_input_hidl_hal_test"
     18 #include <android-base/logging.h>
     19 
     20 #include <android/hardware/tv/input/1.0/types.h>
     21 #include <android/hardware/tv/input/1.0/ITvInput.h>
     22 #include <android/hardware/tv/input/1.0/ITvInputCallback.h>
     23 
     24 #include <VtsHalHidlTargetTestBase.h>
     25 #include <utils/KeyedVector.h>
     26 #include <mutex>
     27 #include <vector>
     28 
     29 using ::android::hardware::tv::input::V1_0::ITvInput;
     30 using ::android::hardware::tv::input::V1_0::ITvInputCallback;
     31 using ::android::hardware::tv::input::V1_0::Result;
     32 using ::android::hardware::tv::input::V1_0::TvInputType;
     33 using ::android::hardware::tv::input::V1_0::TvInputDeviceInfo;
     34 using ::android::hardware::tv::input::V1_0::TvInputEventType;
     35 using ::android::hardware::tv::input::V1_0::TvInputEvent;
     36 using ::android::hardware::tv::input::V1_0::TvStreamConfig;
     37 using ::android::hardware::Return;
     38 using ::android::hardware::Void;
     39 using ::android::hardware::hidl_vec;
     40 using ::android::sp;
     41 
     42 #define WAIT_FOR_EVENT_TIMEOUT 5
     43 #define DEFAULT_ID INT32_MIN
     44 
     45 /* The main test class for TV Input HIDL HAL. */
     46 class TvInputHidlTest : public ::testing::VtsHalHidlTargetTestBase {
     47  public:
     48   virtual void SetUp() override {
     49     tv_input_ = ::testing::VtsHalHidlTargetTestBase::getService<ITvInput>();
     50     ASSERT_NE(tv_input_, nullptr);
     51     tv_input_callback_ = new TvInputCallback(*this);
     52     ASSERT_NE(tv_input_callback_, nullptr);
     53     tv_input_->setCallback(tv_input_callback_);
     54     // All events received within the timeout should be handled.
     55     sleep(WAIT_FOR_EVENT_TIMEOUT);
     56   }
     57 
     58   virtual void TearDown() override {}
     59 
     60   /* Called when a DEVICE_AVAILABLE event is received. */
     61   void onDeviceAvailable(const TvInputDeviceInfo& deviceInfo) {
     62     device_info_.add(deviceInfo.deviceId, deviceInfo);
     63   }
     64 
     65   /* Called when a DEVICE_UNAVAILABLE event is received. */
     66   void onDeviceUnavailable(int32_t deviceId) {
     67     device_info_.removeItem(deviceId);
     68   }
     69 
     70   /* Called when a DEVICE_CONFIGURATIONS_CHANGED event is received. */
     71   Result onStreamConfigurationsChanged(int32_t deviceId) {
     72     return updateStreamConfigurations(deviceId);
     73   }
     74 
     75   /* Gets and updates the stream configurations for a device. */
     76   Result updateStreamConfigurations(int32_t deviceId) {
     77     stream_config_.removeItem(deviceId);
     78     Result result = Result::UNKNOWN;
     79     hidl_vec<TvStreamConfig> list;
     80     tv_input_->getStreamConfigurations(deviceId,
     81         [&result, &list](Result res, hidl_vec<TvStreamConfig> configs) {
     82           result = res;
     83           if (res == Result::OK) {
     84             list = configs;
     85           }
     86         });
     87     if (result == Result::OK) {
     88       stream_config_.add(deviceId, list);
     89     }
     90     return result;
     91   }
     92 
     93   /* Gets and updates the stream configurations for all existing devices. */
     94   void updateAllStreamConfigurations() {
     95     for (size_t i = 0; i < device_info_.size(); i++) {
     96       int32_t device_id = device_info_.keyAt(i);
     97       updateStreamConfigurations(device_id);
     98     }
     99   }
    100 
    101   /* Returns a list of indices of stream_config_ whose corresponding values are not empty. */
    102   std::vector<size_t> getConfigIndices() {
    103     std::vector<size_t> indices;
    104     for (size_t i = 0; i < stream_config_.size(); i++) {
    105       if (stream_config_.valueAt(i).size() != 0) {
    106         indices.push_back(i);
    107       }
    108     }
    109     return indices;
    110   }
    111 
    112   /*
    113    * Returns DEFAULT_ID if there is no missing integer in the range [0, the size of nums).
    114    * Otherwise, returns the smallest missing non-negative integer.
    115    */
    116   int32_t getNumNotIn(std::vector<int32_t>& nums) {
    117     int32_t result = DEFAULT_ID;
    118     int32_t size = static_cast<int32_t>(nums.size());
    119     for (int32_t i = 0; i < size; i++) {
    120       // Put every element to its target position, if possible.
    121       int32_t target_pos = nums[i];
    122       while (target_pos >= 0 && target_pos < size && i != target_pos && nums[i] != nums[target_pos]) {
    123         std::swap(nums[i], nums[target_pos]);
    124         target_pos = nums[i];
    125       }
    126     }
    127 
    128     for (int32_t i = 0; i < size; i++) {
    129       if (nums[i] != i) {
    130         return i;
    131       }
    132     }
    133     return result;
    134   }
    135 
    136   /* A simple test implementation of TvInputCallback for TV Input Events. */
    137   class TvInputCallback : public ITvInputCallback {
    138     public:
    139      TvInputCallback(TvInputHidlTest& parent) : parent_(parent){};
    140 
    141      virtual ~TvInputCallback() = default;
    142 
    143      /*
    144       * Notifies the client that an event has occured. For possible event types,
    145       * check TvInputEventType.
    146   */
    147      Return<void> notify(const TvInputEvent& event) override {
    148        std::unique_lock<std::mutex> lock(parent_.mutex_);
    149        switch(event.type) {
    150          case TvInputEventType::DEVICE_AVAILABLE:
    151            parent_.onDeviceAvailable(event.deviceInfo);
    152            break;
    153          case TvInputEventType::DEVICE_UNAVAILABLE:
    154            parent_.onDeviceUnavailable(event.deviceInfo.deviceId);
    155            break;
    156          case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED:
    157            parent_.onStreamConfigurationsChanged(event.deviceInfo.deviceId);
    158            break;
    159        }
    160        return Void();
    161      };
    162     private:
    163      /* The test contains this callback instance. */
    164      TvInputHidlTest& parent_;
    165   };
    166 
    167   /* The TvInput used for the test. */
    168   sp<ITvInput> tv_input_;
    169 
    170   /* The TvInputCallback used for the test. */
    171   sp<ITvInputCallback> tv_input_callback_;
    172 
    173   /*
    174    * A KeyedVector stores device information of every available device.
    175    * A key is a device ID and the corresponding value is the TvInputDeviceInfo.
    176    */
    177   android::KeyedVector<int32_t, TvInputDeviceInfo> device_info_;
    178 
    179   /*
    180    * A KeyedVector stores a list of stream configurations of every available device.
    181    * A key is a device ID and the corresponding value is the stream configuration list.
    182    */
    183   android::KeyedVector<int32_t, hidl_vec<TvStreamConfig>> stream_config_;
    184 
    185   /* The mutex controls the access of shared data. */
    186   std::mutex mutex_;
    187 };
    188 
    189 
    190 /* A class for test environment setup. */
    191 class TvInputHidlEnvironment : public ::testing::Environment {
    192  public:
    193   virtual void SetUp() {}
    194   virtual void TearDown() {}
    195 
    196  private:
    197 };
    198 
    199 /*
    200  * GetStreamConfigTest:
    201  * Calls updateStreamConfigurations() for each existing device
    202  * Checks returned results
    203  */
    204 TEST_F(TvInputHidlTest, GetStreamConfigTest) {
    205   std::unique_lock<std::mutex> lock(mutex_);
    206   for (size_t i = 0; i < device_info_.size(); i++) {
    207     int32_t device_id = device_info_.keyAt(i);
    208     Result result = updateStreamConfigurations(device_id);
    209     EXPECT_EQ(Result::OK, result);
    210   }
    211 }
    212 
    213 /*
    214  * OpenAndCloseStreamTest:
    215  * Calls openStream() and then closeStream() for each existing stream
    216  * Checks returned results
    217  */
    218 TEST_F(TvInputHidlTest, OpenAndCloseStreamTest) {
    219   std::unique_lock<std::mutex> lock(mutex_);
    220   updateAllStreamConfigurations();
    221   for (size_t j = 0; j < stream_config_.size(); j++) {
    222     int32_t device_id = stream_config_.keyAt(j);
    223     hidl_vec<TvStreamConfig> config = stream_config_.valueAt(j);
    224     for (size_t i = 0; i < config.size(); i++) {
    225       Result result = Result::UNKNOWN;
    226       int32_t stream_id = config[i].streamId;
    227       tv_input_->openStream(device_id, stream_id,
    228           [&result](Result res, const native_handle_t*) {
    229               result = res;
    230           });
    231       EXPECT_EQ(Result::OK, result);
    232 
    233       result = Result::UNKNOWN;
    234       result = tv_input_->closeStream(device_id, stream_id);
    235       EXPECT_EQ(Result::OK, result);
    236     }
    237   }
    238 }
    239 
    240 /*
    241  * InvalidDeviceIdTest:
    242  * Calls updateStreamConfigurations(), openStream(), and closeStream()
    243  * for a non-existing device
    244  * Checks returned results
    245  * The results should be Result::INVALID_ARGUMENTS
    246  */
    247 TEST_F(TvInputHidlTest, InvalidDeviceIdTest) {
    248   std::unique_lock<std::mutex> lock(mutex_);
    249 
    250   std::vector<int32_t> device_ids;
    251   for (size_t i = 0; i < device_info_.size(); i++) {
    252     device_ids.push_back(device_info_.keyAt(i));
    253   }
    254   // Get a non-existing device ID.
    255   int32_t id = getNumNotIn(device_ids);
    256   EXPECT_EQ(Result::INVALID_ARGUMENTS, updateStreamConfigurations(id));
    257 
    258   Result result = Result::UNKNOWN;
    259   int32_t stream_id = 0;
    260   tv_input_->openStream(id, stream_id,
    261       [&result](Result res, const native_handle_t*) {
    262           result = res;
    263       });
    264   EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
    265 
    266   result = Result::UNKNOWN;
    267   result = tv_input_->closeStream(id, stream_id);
    268   EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
    269 }
    270 
    271 /*
    272  * InvalidStreamIdTest:
    273  * Calls openStream(), and closeStream() for a non-existing stream
    274  * Checks returned results
    275  * The results should be Result::INVALID_ARGUMENTS
    276  */
    277 TEST_F(TvInputHidlTest, InvalidStreamIdTest) {
    278   std::unique_lock<std::mutex> lock(mutex_);
    279   if (device_info_.isEmpty()) {
    280     return;
    281   }
    282   updateAllStreamConfigurations();
    283 
    284   int32_t device_id = device_info_.keyAt(0);
    285   // Get a non-existing stream ID.
    286   int32_t id = DEFAULT_ID;
    287   if (stream_config_.indexOfKey(device_id) >= 0) {
    288     std::vector<int32_t> stream_ids;
    289     hidl_vec<TvStreamConfig> config = stream_config_.valueFor(device_id);
    290     for (size_t i = 0; i < config.size(); i++) {
    291       stream_ids.push_back(config[i].streamId);
    292     }
    293     id = getNumNotIn(stream_ids);
    294   }
    295 
    296   Result result = Result::UNKNOWN;
    297   tv_input_->openStream(device_id, id,
    298       [&result](Result res, const native_handle_t*) {
    299           result = res;
    300       });
    301   EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
    302 
    303   result = Result::UNKNOWN;
    304   result = tv_input_->closeStream(device_id, id);
    305   EXPECT_EQ(Result::INVALID_ARGUMENTS, result);
    306 }
    307 
    308 /*
    309  * OpenAnOpenedStreamsTest:
    310  * Calls openStream() twice for a stream (if any)
    311  * Checks returned results
    312  * The result of the second call should be Result::INVALID_STATE
    313  */
    314 TEST_F(TvInputHidlTest, OpenAnOpenedStreamsTest) {
    315   std::unique_lock<std::mutex> lock(mutex_);
    316   updateAllStreamConfigurations();
    317   std::vector<size_t> indices = getConfigIndices();
    318   if (indices.empty()) {
    319     return;
    320   }
    321   int32_t device_id = stream_config_.keyAt(indices[0]);
    322   int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;
    323 
    324   Result result = Result::UNKNOWN;
    325   tv_input_->openStream(device_id, stream_id,
    326       [&result](Result res, const native_handle_t*) {
    327           result = res;
    328       });
    329   EXPECT_EQ(Result::OK, result);
    330 
    331   tv_input_->openStream(device_id, stream_id,
    332       [&result](Result res, const native_handle_t*) {
    333           result = res;
    334       });
    335   EXPECT_EQ(Result::INVALID_STATE, result);
    336 }
    337 
    338 /*
    339  * CloseStreamBeforeOpenTest:
    340  * Calls closeStream() without calling openStream() for a stream (if any)
    341  * Checks the returned result
    342  * The result should be Result::INVALID_STATE
    343  */
    344 TEST_F(TvInputHidlTest, CloseStreamBeforeOpenTest) {
    345   std::unique_lock<std::mutex> lock(mutex_);
    346   updateAllStreamConfigurations();
    347   std::vector<size_t> indices = getConfigIndices();
    348   if (indices.empty()) {
    349     return;
    350   }
    351   int32_t device_id = stream_config_.keyAt(indices[0]);
    352   int32_t stream_id = stream_config_.valueAt(indices[0])[0].streamId;
    353   EXPECT_EQ(Result::INVALID_STATE, tv_input_->closeStream(device_id, stream_id));
    354 }
    355 
    356 int main(int argc, char **argv) {
    357   ::testing::AddGlobalTestEnvironment(new TvInputHidlEnvironment);
    358   ::testing::InitGoogleTest(&argc, argv);
    359   int status = RUN_ALL_TESTS();
    360   ALOGI("Test result = %d", status);
    361   return status;
    362 }
    363 
    364