1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/login/cryptohome_op.h"
6
7 #include <string>
8
9 #include "base/memory/ref_counted.h"
10 #include "base/message_loop.h"
11 #include "chrome/browser/chromeos/cros/mock_library_loader.h"
12 #include "chrome/browser/chromeos/cros/mock_cryptohome_library.h"
13 #include "chrome/browser/chromeos/login/auth_attempt_state.h"
14 #include "chrome/browser/chromeos/login/mock_auth_attempt_state_resolver.h"
15 #include "chrome/browser/chromeos/login/test_attempt_state.h"
16 #include "content/browser/browser_thread.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 using ::testing::AnyNumber;
21 using ::testing::Invoke;
22 using ::testing::Return;
23 using ::testing::_;
24
25 namespace chromeos {
26
27 class CryptohomeOpTest : public ::testing::Test {
28 public:
CryptohomeOpTest()29 CryptohomeOpTest()
30 : message_loop_(MessageLoop::TYPE_UI),
31 ui_thread_(BrowserThread::UI, &message_loop_),
32 io_thread_(BrowserThread::IO),
33 username_("me@nowhere.org"),
34 hash_ascii_("0a010000000000a0"),
35 state_(username_, "", hash_ascii_, "", "", false),
36 resolver_(new MockAuthAttemptStateResolver),
37 mock_library_(new MockCryptohomeLibrary) {
38 }
39
~CryptohomeOpTest()40 virtual ~CryptohomeOpTest() {}
41
SetUp()42 virtual void SetUp() {
43 CrosLibrary::TestApi* test_api = CrosLibrary::Get()->GetTestApi();
44
45 MockLibraryLoader* loader = new MockLibraryLoader();
46 ON_CALL(*loader, Load(_))
47 .WillByDefault(Return(true));
48 EXPECT_CALL(*loader, Load(_))
49 .Times(AnyNumber());
50
51 // Passes ownership of |loader| to CrosLibrary.
52 test_api->SetLibraryLoader(loader, true);
53 // |mock_library_| is mine, though.
54 test_api->SetCryptohomeLibrary(mock_library_.get(), false);
55 mock_library_->SetUp(false, 0);
56
57 io_thread_.Start();
58 }
59
TearDown()60 virtual void TearDown() {
61 // Prevent bogus gMock leak check from firing.
62 chromeos::CrosLibrary::TestApi* test_api =
63 chromeos::CrosLibrary::Get()->GetTestApi();
64 test_api->SetLibraryLoader(NULL, false);
65 }
66
ExpectMigrate(bool passing_old_hash,const std::string & hash)67 void ExpectMigrate(bool passing_old_hash, const std::string& hash) {
68 if (passing_old_hash) {
69 EXPECT_CALL(*(mock_library_.get()), AsyncMigrateKey(username_,
70 hash,
71 hash_ascii_,
72 _))
73 .Times(1)
74 .RetiresOnSaturation();
75 } else {
76 EXPECT_CALL(*(mock_library_.get()), AsyncMigrateKey(username_,
77 hash_ascii_,
78 hash,
79 _))
80 .Times(1)
81 .RetiresOnSaturation();
82 }
83 }
84
ExpectMount()85 void ExpectMount() {
86 EXPECT_CALL(*(mock_library_.get()),
87 AsyncMount(username_, hash_ascii_, true, _))
88 .Times(1)
89 .RetiresOnSaturation();
90 }
91
ExpectMountGuest()92 void ExpectMountGuest() {
93 EXPECT_CALL(*(mock_library_.get()), AsyncMountForBwsi(_))
94 .Times(1)
95 .RetiresOnSaturation();
96 }
97
ExpectRemove()98 void ExpectRemove() {
99 EXPECT_CALL(*(mock_library_.get()), AsyncRemove(username_, _))
100 .Times(1)
101 .RetiresOnSaturation();
102 }
103
ExpectCheckKey()104 void ExpectCheckKey() {
105 EXPECT_CALL(*(mock_library_.get()),
106 AsyncCheckKey(username_, hash_ascii_, _))
107 .Times(1)
108 .RetiresOnSaturation();
109 }
110
RunTest(CryptohomeOp * op,bool outcome,int code)111 void RunTest(CryptohomeOp* op, bool outcome, int code) {
112 mock_library_->SetAsyncBehavior(outcome, code);
113
114 EXPECT_CALL(*(resolver_.get()), Resolve())
115 .Times(1)
116 .RetiresOnSaturation();
117
118 EXPECT_TRUE(op->Initiate());
119 // Force IO thread to finish tasks so I can verify |state_|.
120 io_thread_.Stop();
121
122 EXPECT_EQ(outcome, state_.cryptohome_outcome());
123 EXPECT_EQ(code, state_.cryptohome_code());
124 }
125
126 MessageLoop message_loop_;
127 BrowserThread ui_thread_;
128 BrowserThread io_thread_;
129 std::string username_;
130 std::string hash_ascii_;
131 TestAttemptState state_;
132 scoped_ptr<MockAuthAttemptStateResolver> resolver_;
133 scoped_refptr<CryptohomeOp> op_;
134 scoped_ptr<MockCryptohomeLibrary> mock_library_;
135
136 };
137
TEST_F(CryptohomeOpTest,MountSuccess)138 TEST_F(CryptohomeOpTest, MountSuccess) {
139 ExpectMount();
140 scoped_refptr<CryptohomeOp> op(
141 CryptohomeOp::CreateMountAttempt(&state_, resolver_.get(), true));
142 RunTest(op.get(), true, kCryptohomeMountErrorNone);
143 }
144
TEST_F(CryptohomeOpTest,MountFatal)145 TEST_F(CryptohomeOpTest, MountFatal) {
146 ExpectMount();
147 scoped_refptr<CryptohomeOp> op(
148 CryptohomeOp::CreateMountAttempt(&state_, resolver_.get(), true));
149 RunTest(op.get(), false, kCryptohomeMountErrorFatal);
150 }
151
TEST_F(CryptohomeOpTest,MountKeyFailure)152 TEST_F(CryptohomeOpTest, MountKeyFailure) {
153 ExpectMount();
154 scoped_refptr<CryptohomeOp> op(
155 CryptohomeOp::CreateMountAttempt(&state_, resolver_.get(), true));
156 RunTest(op.get(), false, kCryptohomeMountErrorKeyFailure);
157 }
158
TEST_F(CryptohomeOpTest,MountRecreated)159 TEST_F(CryptohomeOpTest, MountRecreated) {
160 ExpectMount();
161 scoped_refptr<CryptohomeOp> op(
162 CryptohomeOp::CreateMountAttempt(&state_, resolver_.get(), true));
163 RunTest(op.get(), true, kCryptohomeMountErrorRecreated);
164 }
165
TEST_F(CryptohomeOpTest,MountGuestSuccess)166 TEST_F(CryptohomeOpTest, MountGuestSuccess) {
167 ExpectMountGuest();
168 scoped_refptr<CryptohomeOp> op(
169 CryptohomeOp::CreateMountGuestAttempt(&state_, resolver_.get()));
170 RunTest(op.get(), true, kCryptohomeMountErrorNone);
171 }
172
TEST_F(CryptohomeOpTest,MountGuestFatal)173 TEST_F(CryptohomeOpTest, MountGuestFatal) {
174 ExpectMountGuest();
175 scoped_refptr<CryptohomeOp> op(
176 CryptohomeOp::CreateMountGuestAttempt(&state_, resolver_.get()));
177 RunTest(op.get(), false, kCryptohomeMountErrorFatal);
178 }
179
TEST_F(CryptohomeOpTest,MigrateSuccessPassOld)180 TEST_F(CryptohomeOpTest, MigrateSuccessPassOld) {
181 ExpectMigrate(true, "");
182 scoped_refptr<CryptohomeOp> op(
183 CryptohomeOp::CreateMigrateAttempt(&state_, resolver_.get(), true, ""));
184 RunTest(op.get(), true, kCryptohomeMountErrorNone);
185 }
186
TEST_F(CryptohomeOpTest,MigrateSuccessPassNew)187 TEST_F(CryptohomeOpTest, MigrateSuccessPassNew) {
188 ExpectMigrate(false, "");
189 scoped_refptr<CryptohomeOp> op(
190 CryptohomeOp::CreateMigrateAttempt(&state_, resolver_.get(), false, ""));
191 RunTest(op.get(), true, kCryptohomeMountErrorNone);
192 }
193
TEST_F(CryptohomeOpTest,MigrateKeyFailure)194 TEST_F(CryptohomeOpTest, MigrateKeyFailure) {
195 ExpectMigrate(true, "");
196 scoped_refptr<CryptohomeOp> op(
197 CryptohomeOp::CreateMigrateAttempt(&state_, resolver_.get(), true, ""));
198 RunTest(op.get(), false, kCryptohomeMountErrorKeyFailure);
199 }
200
TEST_F(CryptohomeOpTest,RemoveSuccess)201 TEST_F(CryptohomeOpTest, RemoveSuccess) {
202 ExpectRemove();
203 scoped_refptr<CryptohomeOp> op(
204 CryptohomeOp::CreateRemoveAttempt(&state_, resolver_.get()));
205 RunTest(op.get(), true, kCryptohomeMountErrorNone);
206 }
207
TEST_F(CryptohomeOpTest,RemoveFailure)208 TEST_F(CryptohomeOpTest, RemoveFailure) {
209 ExpectRemove();
210 scoped_refptr<CryptohomeOp> op(
211 CryptohomeOp::CreateRemoveAttempt(&state_, resolver_.get()));
212 RunTest(op.get(), false, kCryptohomeMountErrorKeyFailure);
213 }
214
TEST_F(CryptohomeOpTest,CheckKeySuccess)215 TEST_F(CryptohomeOpTest, CheckKeySuccess) {
216 ExpectCheckKey();
217 scoped_refptr<CryptohomeOp> op(
218 CryptohomeOp::CreateCheckKeyAttempt(&state_, resolver_.get()));
219 RunTest(op.get(), true, kCryptohomeMountErrorNone);
220 }
221
TEST_F(CryptohomeOpTest,CheckKeyFailure)222 TEST_F(CryptohomeOpTest, CheckKeyFailure) {
223 ExpectCheckKey();
224 scoped_refptr<CryptohomeOp> op(
225 CryptohomeOp::CreateCheckKeyAttempt(&state_, resolver_.get()));
226 RunTest(op.get(), false, kCryptohomeMountErrorKeyFailure);
227 }
228
229 } // namespace chromeos
230