// Copyright (c) 2012 The Chromium OS 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 "crash-reporter/udev_collector.h"

#include <base/files/file_enumerator.h>
#include <base/files/file_util.h>
#include <base/files/scoped_temp_dir.h>
#include <base/strings/stringprintf.h>
#include <brillo/syslog_logging.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>

#include "crash-reporter/paths.h"
#include "crash-reporter/test_util.h"

using base::FilePath;

namespace {

// Dummy log config file name.
const char kLogConfigFileName[] = "log_config_file";

// Dummy directory for storing device coredumps.
const char kDevCoredumpDirectory[] = "devcoredump";

// A bunch of random rules to put into the dummy log config file.
const char kLogConfigFileContents[] =
    "crash_reporter-udev-collection-change-card0-drm=echo change card0 drm\n"
    "crash_reporter-udev-collection-add-state0-cpu=echo change state0 cpu\n"
    "crash_reporter-udev-collection-devcoredump-iwlwifi=echo devcoredump\n"
    "cros_installer=echo not for udev";

const char kCrashLogFilePattern[] = "*.log.gz";
const char kDevCoredumpFilePattern[] = "*.devcore";

// Dummy content for device coredump data file.
const char kDevCoredumpDataContents[] = "coredump";

// Content for failing device's uevent file.
const char kFailingDeviceUeventContents[] = "DRIVER=iwlwifi\n";

bool s_consent_given = true;

bool IsMetrics() {
  return s_consent_given;
}

// Returns the number of files found in the given path that matches the
// specified file name pattern.
int GetNumFiles(const FilePath& path, const std::string& file_pattern) {
  base::FileEnumerator enumerator(path, false, base::FileEnumerator::FILES,
                                  file_pattern);
  int num_files = 0;
  for (FilePath file_path = enumerator.Next(); !file_path.value().empty();
       file_path = enumerator.Next()) {
    num_files++;
  }
  return num_files;
}

}  // namespace

class UdevCollectorMock : public UdevCollector {
 public:
  MOCK_METHOD(void, SetUpDBus, (), (override));
};

class UdevCollectorTest : public ::testing::Test {
 protected:
  base::ScopedTempDir temp_dir_generator_;

  void HandleCrash(const std::string& udev_event) {
    collector_.HandleCrash(udev_event);
  }

  void GenerateDevCoredump(const std::string& device_name) {
    // Generate coredump data file.
    ASSERT_TRUE(CreateDirectory(FilePath(
        base::StringPrintf("%s/%s", collector_.dev_coredump_directory_.c_str(),
                           device_name.c_str()))));
    FilePath data_path = FilePath(base::StringPrintf(
        "%s/%s/data", collector_.dev_coredump_directory_.c_str(),
        device_name.c_str()));
    ASSERT_TRUE(test_util::CreateFile(data_path, kDevCoredumpDataContents));
    // Generate uevent file for failing device.
    ASSERT_TRUE(CreateDirectory(FilePath(base::StringPrintf(
        "%s/%s/failing_device", collector_.dev_coredump_directory_.c_str(),
        device_name.c_str()))));
    FilePath uevent_path = FilePath(base::StringPrintf(
        "%s/%s/failing_device/uevent",
        collector_.dev_coredump_directory_.c_str(), device_name.c_str()));
    ASSERT_TRUE(
        test_util::CreateFile(uevent_path, kFailingDeviceUeventContents));
  }

  void SetUpCollector(UdevCollectorMock* collector) {
    EXPECT_CALL(*collector, SetUpDBus()).WillRepeatedly(testing::Return());
    collector->Initialize(IsMetrics, false);

    collector->log_config_path_ = log_config_path_;
    collector->set_crash_directory_for_test(temp_dir_generator_.GetPath());

    FilePath dev_coredump_path =
        temp_dir_generator_.GetPath().Append(kDevCoredumpDirectory);
    collector->dev_coredump_directory_ = dev_coredump_path.value();
  }

 private:
  void SetUp() override {
    s_consent_given = true;

    ASSERT_TRUE(temp_dir_generator_.CreateUniqueTempDir());
    log_config_path_ = temp_dir_generator_.GetPath().Append(kLogConfigFileName);

    SetUpCollector(&collector_);
    // Write to a dummy log config file.
    ASSERT_TRUE(
        test_util::CreateFile(log_config_path_, kLogConfigFileContents));
    brillo::ClearLog();
  }

  FilePath log_config_path_;
  UdevCollectorMock collector_;
};

TEST_F(UdevCollectorTest, TestNoConsent) {
  s_consent_given = false;
  HandleCrash("ACTION=change:KERNEL=card0:SUBSYSTEM=drm");
  EXPECT_EQ(0,
            GetNumFiles(temp_dir_generator_.GetPath(), kCrashLogFilePattern));
}

TEST_F(UdevCollectorTest, TestNoMatch) {
  // No rule should match this.
  HandleCrash("ACTION=change:KERNEL=foo:SUBSYSTEM=bar");
  EXPECT_EQ(0,
            GetNumFiles(temp_dir_generator_.GetPath(), kCrashLogFilePattern));
}

TEST_F(UdevCollectorTest, TestMatches) {
  // Try multiple udev events in sequence.  The number of log files generated
  // should increase.
  HandleCrash("ACTION=change:KERNEL=card0:SUBSYSTEM=drm");
  EXPECT_EQ(1,
            GetNumFiles(temp_dir_generator_.GetPath(), kCrashLogFilePattern));

  // Each collector is only allowed to handle one crash, so create a second
  // collector for the second crash.
  UdevCollectorMock second_collector;
  SetUpCollector(&second_collector);
  second_collector.HandleCrash("ACTION=add:KERNEL=state0:SUBSYSTEM=cpu");
  EXPECT_EQ(2,
            GetNumFiles(temp_dir_generator_.GetPath(), kCrashLogFilePattern));
}

TEST_F(UdevCollectorTest, TestDevCoredump) {
  GenerateDevCoredump("devcd0");
  HandleCrash("ACTION=add:KERNEL_NUMBER=0:SUBSYSTEM=devcoredump");
  // IsDeveloperImage() returns false while running this test so devcoredumps
  // will not be added to the crash directory.
  EXPECT_EQ(
      0, GetNumFiles(temp_dir_generator_.GetPath(), kDevCoredumpFilePattern));
  GenerateDevCoredump("devcd1");
  // Each collector is only allowed to handle one crash, so create a second
  // collector for the second crash.
  UdevCollectorMock second_collector;
  SetUpCollector(&second_collector);
  second_collector.HandleCrash(
      "ACTION=add:KERNEL_NUMBER=1:SUBSYSTEM=devcoredump");
  EXPECT_EQ(
      0, GetNumFiles(temp_dir_generator_.GetPath(), kDevCoredumpFilePattern));
}

// TODO(sque, crosbug.com/32238) - test wildcard cases, multiple identical udev
// events.
