Line data Source code
1 : // Copyright (C) 2018 The Android Open Source Project
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : package com.google.gerrit.acceptance.testsuite.account;
16 :
17 : import static com.google.common.base.Preconditions.checkState;
18 : import static com.google.common.collect.ImmutableSet.toImmutableSet;
19 :
20 : import com.google.common.collect.ImmutableSet;
21 : import com.google.common.collect.Sets;
22 : import com.google.gerrit.entities.Account;
23 : import com.google.gerrit.server.ServerInitiated;
24 : import com.google.gerrit.server.account.AccountDelta;
25 : import com.google.gerrit.server.account.AccountState;
26 : import com.google.gerrit.server.account.Accounts;
27 : import com.google.gerrit.server.account.AccountsUpdate;
28 : import com.google.gerrit.server.account.AccountsUpdate.ConfigureDeltaFromState;
29 : import com.google.gerrit.server.account.externalids.ExternalId;
30 : import com.google.gerrit.server.account.externalids.ExternalIdFactory;
31 : import com.google.gerrit.server.notedb.Sequences;
32 : import com.google.inject.Inject;
33 : import java.io.IOException;
34 : import java.util.Optional;
35 : import java.util.function.Consumer;
36 : import org.eclipse.jgit.errors.ConfigInvalidException;
37 :
38 : /**
39 : * The implementation of {@code AccountOperations}.
40 : *
41 : * <p>There is only one implementation of {@code AccountOperations}. Nevertheless, we keep the
42 : * separation between interface and implementation to enhance clarity.
43 : */
44 : public class AccountOperationsImpl implements AccountOperations {
45 : private final Accounts accounts;
46 : private final AccountsUpdate accountsUpdate;
47 : private final Sequences seq;
48 : private final ExternalIdFactory externalIdFactory;
49 :
50 : @Inject
51 : public AccountOperationsImpl(
52 : Accounts accounts,
53 : @ServerInitiated AccountsUpdate accountsUpdate,
54 : Sequences seq,
55 138 : ExternalIdFactory externalIdFactory) {
56 138 : this.accounts = accounts;
57 138 : this.accountsUpdate = accountsUpdate;
58 138 : this.seq = seq;
59 138 : this.externalIdFactory = externalIdFactory;
60 138 : }
61 :
62 : @Override
63 : public PerAccountOperations account(Account.Id accountId) {
64 132 : return new PerAccountOperationsImpl(accountId);
65 : }
66 :
67 : @Override
68 : public TestAccountCreation.Builder newAccount() {
69 11 : return TestAccountCreation.builder(this::createAccount);
70 : }
71 :
72 : private Account.Id createAccount(TestAccountCreation testAccountCreation) throws Exception {
73 11 : Account.Id accountId = Account.id(seq.nextAccountId());
74 11 : Consumer<AccountDelta.Builder> accountCreation =
75 11 : deltaBuilder -> initAccountDelta(deltaBuilder, testAccountCreation, accountId);
76 11 : AccountState createdAccount =
77 11 : accountsUpdate.insert("Create Test Account", accountId, accountCreation);
78 11 : return createdAccount.account().id();
79 : }
80 :
81 : private void initAccountDelta(
82 : AccountDelta.Builder builder, TestAccountCreation accountCreation, Account.Id accountId) {
83 11 : accountCreation.fullname().ifPresent(builder::setFullName);
84 11 : accountCreation.preferredEmail().ifPresent(e -> setPreferredEmail(builder, accountId, e));
85 11 : String httpPassword = accountCreation.httpPassword().orElse(null);
86 11 : accountCreation.username().ifPresent(u -> setUsername(builder, accountId, u, httpPassword));
87 11 : accountCreation.status().ifPresent(builder::setStatus);
88 11 : accountCreation.active().ifPresent(builder::setActive);
89 11 : accountCreation
90 11 : .secondaryEmails()
91 11 : .forEach(
92 : secondaryEmail ->
93 1 : builder.addExternalId(externalIdFactory.createEmail(accountId, secondaryEmail)));
94 11 : }
95 :
96 : private void setPreferredEmail(
97 : AccountDelta.Builder builder, Account.Id accountId, String preferredEmail) {
98 4 : builder
99 4 : .setPreferredEmail(preferredEmail)
100 4 : .addExternalId(externalIdFactory.createEmail(accountId, preferredEmail));
101 4 : }
102 :
103 : private void setUsername(
104 : AccountDelta.Builder builder, Account.Id accountId, String username, String httpPassword) {
105 5 : builder.addExternalId(externalIdFactory.createUsername(username, accountId, httpPassword));
106 5 : }
107 :
108 : private class PerAccountOperationsImpl implements PerAccountOperations {
109 : private final Account.Id accountId;
110 :
111 132 : PerAccountOperationsImpl(Account.Id accountId) {
112 132 : this.accountId = accountId;
113 132 : }
114 :
115 : @Override
116 : public boolean exists() {
117 0 : return getAccountState(accountId).isPresent();
118 : }
119 :
120 : @Override
121 : public TestAccount get() {
122 132 : AccountState account =
123 132 : getAccountState(accountId)
124 132 : .orElseThrow(
125 1 : () -> new IllegalStateException("Tried to get non-existing test account"));
126 132 : return toTestAccount(account);
127 : }
128 :
129 : private Optional<AccountState> getAccountState(Account.Id accountId) {
130 : try {
131 132 : return accounts.get(accountId);
132 0 : } catch (IOException | ConfigInvalidException e) {
133 0 : throw new IllegalStateException(e);
134 : }
135 : }
136 :
137 : private TestAccount toTestAccount(AccountState accountState) {
138 132 : Account account = accountState.account();
139 132 : return TestAccount.builder()
140 132 : .accountId(account.id())
141 132 : .preferredEmail(Optional.ofNullable(account.preferredEmail()))
142 132 : .fullname(Optional.ofNullable(account.fullName()))
143 132 : .username(accountState.userName())
144 132 : .active(accountState.account().isActive())
145 132 : .emails(ExternalId.getEmails(accountState.externalIds()).collect(toImmutableSet()))
146 132 : .build();
147 : }
148 :
149 : @Override
150 : public TestAccountUpdate.Builder forUpdate() {
151 3 : return TestAccountUpdate.builder(this::updateAccount);
152 : }
153 :
154 : private void updateAccount(TestAccountUpdate accountUpdate)
155 : throws IOException, ConfigInvalidException {
156 3 : ConfigureDeltaFromState configureDeltaFromState =
157 3 : (accountState, deltaBuilder) -> fillBuilder(deltaBuilder, accountUpdate, accountState);
158 3 : Optional<AccountState> updatedAccount = updateAccount(configureDeltaFromState);
159 3 : checkState(updatedAccount.isPresent(), "Tried to update non-existing test account");
160 3 : }
161 :
162 : private Optional<AccountState> updateAccount(ConfigureDeltaFromState configureDeltaFromState)
163 : throws IOException, ConfigInvalidException {
164 4 : return accountsUpdate.update("Update Test Account", accountId, configureDeltaFromState);
165 : }
166 :
167 : private void fillBuilder(
168 : AccountDelta.Builder builder, TestAccountUpdate accountUpdate, AccountState accountState) {
169 3 : accountUpdate.fullname().ifPresent(builder::setFullName);
170 3 : accountUpdate.preferredEmail().ifPresent(e -> setPreferredEmail(builder, accountId, e));
171 3 : String httpPassword = accountUpdate.httpPassword().orElse(null);
172 3 : accountUpdate.username().ifPresent(u -> setUsername(builder, accountId, u, httpPassword));
173 3 : accountUpdate.status().ifPresent(builder::setStatus);
174 3 : accountUpdate.active().ifPresent(builder::setActive);
175 :
176 3 : ImmutableSet<String> secondaryEmails = getSecondaryEmails(accountUpdate, accountState);
177 3 : ImmutableSet<String> newSecondaryEmails =
178 3 : ImmutableSet.copyOf(accountUpdate.secondaryEmailsModification().apply(secondaryEmails));
179 3 : if (!secondaryEmails.equals(newSecondaryEmails)) {
180 0 : setSecondaryEmails(builder, accountUpdate, accountState, newSecondaryEmails);
181 : }
182 3 : }
183 :
184 : private ImmutableSet<String> getSecondaryEmails(
185 : TestAccountUpdate accountUpdate, AccountState accountState) {
186 3 : ImmutableSet<String> allEmails =
187 3 : ExternalId.getEmails(accountState.externalIds()).collect(toImmutableSet());
188 3 : if (accountUpdate.preferredEmail().isPresent()) {
189 0 : return ImmutableSet.copyOf(
190 0 : Sets.difference(allEmails, ImmutableSet.of(accountUpdate.preferredEmail().get())));
191 3 : } else if (accountState.account().preferredEmail() != null) {
192 3 : return ImmutableSet.copyOf(
193 3 : Sets.difference(allEmails, ImmutableSet.of(accountState.account().preferredEmail())));
194 : }
195 0 : return allEmails;
196 : }
197 :
198 : private void setSecondaryEmails(
199 : AccountDelta.Builder builder,
200 : TestAccountUpdate accountUpdate,
201 : AccountState accountState,
202 : ImmutableSet<String> newSecondaryEmails) {
203 : // delete all external IDs of SCHEME_MAILTO scheme, then add back SCHEME_MAILTO external IDs
204 : // for the new secondary emails and the preferred email
205 0 : builder.deleteExternalIds(
206 0 : accountState.externalIds().stream()
207 0 : .filter(e -> e.isScheme(ExternalId.SCHEME_MAILTO))
208 0 : .collect(toImmutableSet()));
209 0 : builder.addExternalIds(
210 0 : newSecondaryEmails.stream()
211 0 : .map(secondaryEmail -> externalIdFactory.createEmail(accountId, secondaryEmail))
212 0 : .collect(toImmutableSet()));
213 0 : if (accountUpdate.preferredEmail().isPresent()) {
214 0 : builder.addExternalId(
215 0 : externalIdFactory.createEmail(accountId, accountUpdate.preferredEmail().get()));
216 0 : } else if (accountState.account().preferredEmail() != null) {
217 0 : builder.addExternalId(
218 0 : externalIdFactory.createEmail(accountId, accountState.account().preferredEmail()));
219 : }
220 0 : }
221 :
222 : @Override
223 : public TestAccountInvalidation.Builder forInvalidation() {
224 1 : return TestAccountInvalidation.builder(this::invalidateAccount);
225 : }
226 :
227 : private void invalidateAccount(TestAccountInvalidation testAccountInvalidation)
228 : throws Exception {
229 1 : Optional<AccountState> accountState = getAccountState(accountId);
230 1 : checkState(accountState.isPresent(), "Tried to invalidate a non-existing test account");
231 :
232 1 : if (testAccountInvalidation.preferredEmailWithoutExternalId().isPresent()) {
233 1 : updateAccount(
234 : (account, deltaBuilder) ->
235 1 : deltaBuilder.setPreferredEmail(
236 1 : testAccountInvalidation.preferredEmailWithoutExternalId().get()));
237 : }
238 1 : }
239 : }
240 : }
|