// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/sessions/model/web_session_state_cache.h"
#import <Foundation/Foundation.h>
#import "base/apple/foundation_util.h"
#import "base/files/file_util.h"
#import "base/path_service.h"
#import "base/strings/stringprintf.h"
#import "base/strings/sys_string_conversions.h"
#import "base/task/thread_pool/thread_pool_instance.h"
#import "base/test/ios/wait_util.h"
#import "base/time/time.h"
#import "ios/chrome/browser/sessions/model/session_constants.h"
#import "ios/chrome/browser/shared/model/profile/test/test_profile_ios.h"
#import "ios/web/public/test/web_task_environment.h"
#import "ios/web/public/web_state.h"
#import "testing/gtest_mac.h"
#import "testing/platform_test.h"
using base::test::ios::WaitUntilConditionOrTimeout;
namespace {
constexpr base::TimeDelta kRemoveSessionStateDataDelay = base::Seconds(15);
class WebSessionStateCacheTest : public PlatformTest {
protected:
void SetUp() override {
PlatformTest::SetUp();
TestChromeBrowserState::Builder test_cbs_builder;
chrome_browser_state_ = std::move(test_cbs_builder).Build();
sessionCache_ = [[WebSessionStateCache alloc]
initWithBrowserState:chrome_browser_state_.get()];
web::WebState::CreateParams createParams(chrome_browser_state_.get());
web_state_ = web::WebState::Create(createParams);
session_cache_directory_ =
chrome_browser_state_->GetStatePath().Append(kLegacyWebSessionsDirname);
}
bool StorageExists() {
std::string identifier = base::StringPrintf(
"%08u",
static_cast<uint32_t>(web_state_->GetUniqueIdentifier().identifier()));
base::FilePath file_path = session_cache_directory_.Append(identifier);
return base::PathExists(file_path);
}
void TearDown() override {
[sessionCache_ shutdown];
sessionCache_ = nil;
PlatformTest::TearDown();
}
WebSessionStateCache* GetSessionCache() { return sessionCache_; }
// Flushes all the runloops internally used by the cache.
void FlushRunLoops() {
base::ThreadPoolInstance::Get()->FlushForTesting();
base::RunLoop().RunUntilIdle();
}
base::FilePath session_cache_directory_;
std::unique_ptr<web::WebState> web_state_;
web::WebTaskEnvironment task_environment_;
std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
WebSessionStateCache* sessionCache_;
};
// Tests that the expected webState storage file is added and removed as
// expected.
TEST_F(WebSessionStateCacheTest, CacheAddAndRemove) {
WebSessionStateCache* cache = GetSessionCache();
const char data_str[] = "foo";
NSData* data = [NSData dataWithBytes:data_str length:strlen(data_str)];
EXPECT_FALSE(StorageExists());
[cache persistSessionStateData:data
forWebStateID:web_state_->GetUniqueIdentifier()];
FlushRunLoops();
EXPECT_TRUE(StorageExists());
NSData* data_back =
[cache sessionStateDataForWebStateID:web_state_->GetUniqueIdentifier()];
EXPECT_EQ(data_str,
std::string(reinterpret_cast<const char*>(data_back.bytes),
data_back.length));
[cache removeSessionStateDataForWebStateID:web_state_->GetUniqueIdentifier()
incognito:web_state_->GetBrowserState()
->IsOffTheRecord()];
FlushRunLoops();
EXPECT_FALSE(StorageExists());
}
// Tests that the expected webState storage file is removed on a delay.
TEST_F(WebSessionStateCacheTest, CacheDelayRemove) {
WebSessionStateCache* cache = GetSessionCache();
const char data_str[] = "foo";
NSData* data = [NSData dataWithBytes:data_str length:strlen(data_str)];
EXPECT_FALSE(StorageExists());
[cache persistSessionStateData:data
forWebStateID:web_state_->GetUniqueIdentifier()];
FlushRunLoops();
EXPECT_TRUE(StorageExists());
[cache setDelayRemove:true];
[cache removeSessionStateDataForWebStateID:web_state_->GetUniqueIdentifier()
incognito:web_state_->GetBrowserState()
->IsOffTheRecord()];
FlushRunLoops();
[cache setDelayRemove:false];
EXPECT_TRUE(StorageExists());
EXPECT_TRUE(WaitUntilConditionOrTimeout(kRemoveSessionStateDataDelay, ^bool {
FlushRunLoops();
return !StorageExists();
}));
}
} // namespace