Skip to content

Commit ab758bd

Browse files
committed
address review comment, add unit test
1 parent 877dccb commit ab758bd

File tree

10 files changed

+300
-21
lines changed

10 files changed

+300
-21
lines changed

api/src/main/java/org/apache/cloudstack/api/response/LoginCmdResponse.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ public Boolean getPasswordChangeRequired() {
232232
return passwordChangeRequired;
233233
}
234234

235-
public void setPasswordChangeRequired(String passwordChangeRequired) {
236-
this.passwordChangeRequired = Boolean.parseBoolean(passwordChangeRequired);
235+
public void setPasswordChangeRequired(Boolean passwordChangeRequired) {
236+
this.passwordChangeRequired = passwordChangeRequired;
237237
}
238238
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
package org.apache.cloudstack.api.command.admin.user;
21+
22+
import org.apache.cloudstack.api.ApiCommandResourceType;
23+
import org.junit.Assert;
24+
import org.junit.Test;
25+
import org.junit.runner.RunWith;
26+
import org.mockito.InjectMocks;
27+
import org.mockito.junit.MockitoJUnitRunner;
28+
import org.springframework.test.util.ReflectionTestUtils;
29+
30+
@RunWith(MockitoJUnitRunner.class)
31+
public class UpdateUserCmdTest {
32+
@InjectMocks
33+
private UpdateUserCmd cmd;
34+
35+
@Test
36+
public void testGetApiResourceId() {
37+
Long userId = 99L;
38+
cmd.setId(userId);
39+
Assert.assertEquals(userId, cmd.getApiResourceId());
40+
}
41+
42+
@Test
43+
public void testGetApiResourceType() {
44+
Assert.assertEquals(ApiCommandResourceType.User, cmd.getApiResourceType());
45+
}
46+
47+
@Test
48+
public void testIsPasswordChangeRequired_True() {
49+
ReflectionTestUtils.setField(cmd, "passwordChangeRequired", Boolean.TRUE);
50+
Assert.assertTrue(cmd.isPasswordChangeRequired());
51+
}
52+
53+
@Test
54+
public void testIsPasswordChangeRequired_False() {
55+
ReflectionTestUtils.setField(cmd, "passwordChangeRequired", Boolean.FALSE);
56+
Assert.assertFalse(cmd.isPasswordChangeRequired());
57+
}
58+
59+
@Test
60+
public void testIsPasswordChangeRequired_Null() {
61+
ReflectionTestUtils.setField(cmd, "passwordChangeRequired", null);
62+
Assert.assertFalse(cmd.isPasswordChangeRequired());
63+
}
64+
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.apache.cloudstack.api.response;
19+
20+
21+
import org.junit.Assert;
22+
import org.junit.Test;
23+
24+
public class LoginCmdResponseTest {
25+
26+
@Test
27+
public void testAllGettersAndSetters() {
28+
LoginCmdResponse response = new LoginCmdResponse();
29+
30+
response.setUsername("user1");
31+
response.setUserId("100");
32+
response.setDomainId("200");
33+
response.setTimeout(3600);
34+
response.setAccount("account1");
35+
response.setFirstName("John");
36+
response.setLastName("Doe");
37+
response.setType("admin");
38+
response.setTimeZone("UTC");
39+
response.setTimeZoneOffset("+00:00");
40+
response.setRegistered("true");
41+
response.setSessionKey("session-key");
42+
response.set2FAenabled("true");
43+
response.set2FAverfied("false");
44+
response.setProviderFor2FA("totp");
45+
response.setIssuerFor2FA("cloudstack");
46+
response.setManagementServerId("ms-1");
47+
48+
Assert.assertEquals("user1", response.getUsername());
49+
Assert.assertEquals("100", response.getUserId());
50+
Assert.assertEquals("200", response.getDomainId());
51+
Assert.assertEquals(Integer.valueOf(3600), response.getTimeout());
52+
Assert.assertEquals("account1", response.getAccount());
53+
Assert.assertEquals("John", response.getFirstName());
54+
Assert.assertEquals("Doe", response.getLastName());
55+
Assert.assertEquals("admin", response.getType());
56+
Assert.assertEquals("UTC", response.getTimeZone());
57+
Assert.assertEquals("+00:00", response.getTimeZoneOffset());
58+
Assert.assertEquals("true", response.getRegistered());
59+
Assert.assertEquals("session-key", response.getSessionKey());
60+
Assert.assertEquals("true", response.is2FAenabled());
61+
Assert.assertEquals("false", response.is2FAverfied());
62+
Assert.assertEquals("totp", response.getProviderFor2FA());
63+
Assert.assertEquals("cloudstack", response.getIssuerFor2FA());
64+
Assert.assertEquals("ms-1", response.getManagementServerId());
65+
}
66+
67+
@Test
68+
public void testPasswordChangeRequired_True() {
69+
LoginCmdResponse response = new LoginCmdResponse();
70+
response.setPasswordChangeRequired(true);
71+
Assert.assertTrue(response.getPasswordChangeRequired());
72+
}
73+
74+
@Test
75+
public void testPasswordChangeRequired_False() {
76+
LoginCmdResponse response = new LoginCmdResponse();
77+
response.setPasswordChangeRequired(false);
78+
Assert.assertFalse(response.getPasswordChangeRequired());
79+
}
80+
81+
@Test
82+
public void testPasswordChangeRequired_Null() {
83+
LoginCmdResponse response = new LoginCmdResponse();
84+
response.setPasswordChangeRequired(null);
85+
Assert.assertNull("Boolean.parseBoolean(null) should return null", response.getPasswordChangeRequired());
86+
}
87+
}

server/src/main/java/com/cloud/api/ApiServer.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1230,8 +1230,8 @@ private ResponseObject createLoginResponse(HttpSession session) {
12301230
if (ApiConstants.MANAGEMENT_SERVER_ID.equalsIgnoreCase(attrName)) {
12311231
response.setManagementServerId(attrObj.toString());
12321232
}
1233-
if (PASSWORD_CHANGE_REQUIRED.equalsIgnoreCase(attrName)) {
1234-
response.setPasswordChangeRequired(attrObj.toString());
1233+
if (PASSWORD_CHANGE_REQUIRED.equalsIgnoreCase(attrName) && attrObj instanceof Boolean) {
1234+
response.setPasswordChangeRequired((Boolean) attrObj);
12351235
}
12361236
}
12371237
}

server/src/test/java/com/cloud/api/ApiServerTest.java

Lines changed: 112 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,21 @@
1717
package com.cloud.api;
1818

1919
import com.cloud.domain.Domain;
20+
import com.cloud.domain.DomainVO;
21+
import com.cloud.exception.CloudAuthenticationException;
2022
import com.cloud.user.Account;
23+
import com.cloud.user.AccountManager;
24+
import com.cloud.user.DomainManager;
2125
import com.cloud.user.User;
2226
import com.cloud.user.UserAccount;
27+
import com.cloud.user.UserVO;
2328
import com.cloud.utils.exception.CloudRuntimeException;
29+
30+
import org.apache.cloudstack.api.ApiConstants;
31+
import org.apache.cloudstack.api.ResponseObject;
32+
import org.apache.cloudstack.api.response.LoginCmdResponse;
2433
import org.apache.cloudstack.framework.config.ConfigKey;
34+
import org.apache.cloudstack.resourcedetail.UserDetailVO;
2535
import org.apache.cloudstack.user.UserPasswordResetManager;
2636
import org.junit.AfterClass;
2737
import org.junit.Assert;
@@ -35,10 +45,22 @@
3545
import org.mockito.junit.MockitoJUnitRunner;
3646

3747
import java.lang.reflect.Field;
48+
import java.net.InetAddress;
3849
import java.util.ArrayList;
50+
import java.util.Collections;
51+
import java.util.HashMap;
3952
import java.util.List;
53+
import java.util.Map;
4054

55+
import static org.apache.cloudstack.api.ApiConstants.PASSWORD_CHANGE_REQUIRED;
4156
import static org.apache.cloudstack.user.UserPasswordResetManager.UserPasswordResetEnabled;
57+
import static org.mockito.ArgumentMatchers.any;
58+
import static org.mockito.ArgumentMatchers.anyLong;
59+
import static org.mockito.ArgumentMatchers.anyString;
60+
import static org.mockito.ArgumentMatchers.eq;
61+
import static org.mockito.Mockito.mock;
62+
63+
import javax.servlet.http.HttpSession;
4264

4365
@RunWith(MockitoJUnitRunner.class)
4466
public class ApiServerTest {
@@ -49,6 +71,15 @@ public class ApiServerTest {
4971
@Mock
5072
UserPasswordResetManager userPasswordResetManager;
5173

74+
@Mock
75+
DomainManager domainManager;
76+
77+
@Mock
78+
AccountManager accountManager;
79+
80+
@Mock
81+
HttpSession session;
82+
5283
@BeforeClass
5384
public static void beforeClass() throws Exception {
5485
overrideDefaultConfigValue(UserPasswordResetEnabled, "_value", true);
@@ -96,8 +127,8 @@ public void testSetupIntegrationPortListenerValidPort() {
96127

97128
@Test
98129
public void testForgotPasswordSuccess() {
99-
UserAccount userAccount = Mockito.mock(UserAccount.class);
100-
Domain domain = Mockito.mock(Domain.class);
130+
UserAccount userAccount = mock(UserAccount.class);
131+
Domain domain = mock(Domain.class);
101132

102133
Mockito.when(userAccount.getEmail()).thenReturn("test@test.com");
103134
Mockito.when(userAccount.getState()).thenReturn("ENABLED");
@@ -110,17 +141,17 @@ public void testForgotPasswordSuccess() {
110141

111142
@Test(expected = CloudRuntimeException.class)
112143
public void testForgotPasswordFailureNoEmail() {
113-
UserAccount userAccount = Mockito.mock(UserAccount.class);
114-
Domain domain = Mockito.mock(Domain.class);
144+
UserAccount userAccount = mock(UserAccount.class);
145+
Domain domain = mock(Domain.class);
115146

116147
Mockito.when(userAccount.getEmail()).thenReturn("");
117148
apiServer.forgotPassword(userAccount, domain);
118149
}
119150

120151
@Test(expected = CloudRuntimeException.class)
121152
public void testForgotPasswordFailureDisabledUser() {
122-
UserAccount userAccount = Mockito.mock(UserAccount.class);
123-
Domain domain = Mockito.mock(Domain.class);
153+
UserAccount userAccount = mock(UserAccount.class);
154+
Domain domain = mock(Domain.class);
124155

125156
Mockito.when(userAccount.getEmail()).thenReturn("test@test.com");
126157
Mockito.when(userAccount.getState()).thenReturn("DISABLED");
@@ -129,8 +160,8 @@ public void testForgotPasswordFailureDisabledUser() {
129160

130161
@Test(expected = CloudRuntimeException.class)
131162
public void testForgotPasswordFailureDisabledAccount() {
132-
UserAccount userAccount = Mockito.mock(UserAccount.class);
133-
Domain domain = Mockito.mock(Domain.class);
163+
UserAccount userAccount = mock(UserAccount.class);
164+
Domain domain = mock(Domain.class);
134165

135166
Mockito.when(userAccount.getEmail()).thenReturn("test@test.com");
136167
Mockito.when(userAccount.getState()).thenReturn("ENABLED");
@@ -140,8 +171,8 @@ public void testForgotPasswordFailureDisabledAccount() {
140171

141172
@Test(expected = CloudRuntimeException.class)
142173
public void testForgotPasswordFailureInactiveDomain() {
143-
UserAccount userAccount = Mockito.mock(UserAccount.class);
144-
Domain domain = Mockito.mock(Domain.class);
174+
UserAccount userAccount = mock(UserAccount.class);
175+
Domain domain = mock(Domain.class);
145176

146177
Mockito.when(userAccount.getEmail()).thenReturn("test@test.com");
147178
Mockito.when(userAccount.getState()).thenReturn("ENABLED");
@@ -153,8 +184,8 @@ public void testForgotPasswordFailureInactiveDomain() {
153184
@Test
154185
public void testVerifyApiKeyAccessAllowed() {
155186
Long domainId = 1L;
156-
User user = Mockito.mock(User.class);
157-
Account account = Mockito.mock(Account.class);
187+
User user = mock(User.class);
188+
Account account = mock(Account.class);
158189

159190
Mockito.when(user.getApiKeyAccess()).thenReturn(true);
160191
Assert.assertEquals(true, apiServer.verifyApiKeyAccessAllowed(user, account));
@@ -176,4 +207,73 @@ public void testVerifyApiKeyAccessAllowed() {
176207
Mockito.when(account.getApiKeyAccess()).thenReturn(null);
177208
Assert.assertEquals(true, apiServer.verifyApiKeyAccessAllowed(user, account));
178209
}
210+
211+
@Test
212+
public void testLoginUserSuccess() throws Exception {
213+
String username = "user";
214+
String password = "password";
215+
Long domainId = 1L;
216+
String domainPath = "/";
217+
InetAddress loginIp = InetAddress.getByName("127.0.0.1");
218+
Map<String, Object[]> requestParams = new HashMap<>();
219+
220+
DomainVO domain = mock(DomainVO.class);
221+
Mockito.when(domain.getId()).thenReturn(domainId);
222+
Mockito.when(domain.getUuid()).thenReturn("domain-uuid");
223+
224+
Mockito.when(domainManager.findDomainByIdOrPath(domainId, domainPath)).thenReturn(domain);
225+
Mockito.when(domainManager.getDomain(domainId)).thenReturn(domain);
226+
227+
UserAccount userAccount = mock(UserAccount.class);
228+
Mockito.when(userAccount.getId()).thenReturn(100L);
229+
Mockito.when(userAccount.getAccountId()).thenReturn(200L);
230+
Mockito.when(userAccount.getUsername()).thenReturn(username);
231+
Mockito.when(userAccount.getFirstname()).thenReturn("First");
232+
Mockito.when(userAccount.getLastname()).thenReturn("Last");
233+
Mockito.when(userAccount.getTimezone()).thenReturn("UTC");
234+
Mockito.when(userAccount.getRegistrationToken()).thenReturn("token");
235+
Mockito.when(userAccount.isRegistered()).thenReturn(true);
236+
Mockito.when(userAccount.getDomainId()).thenReturn(domainId);
237+
Map<String, String> userAccDetails = new HashMap<>();
238+
userAccDetails.put(UserDetailVO.PasswordChangeRequired, "true");
239+
Mockito.when(userAccount.getDetails()).thenReturn(userAccDetails);
240+
241+
Mockito.when(accountManager.authenticateUser(username, password, domainId, loginIp, requestParams)).thenReturn(userAccount);
242+
Mockito.when(accountManager.clearUserTwoFactorAuthenticationInSetupStateOnLogin(userAccount)).thenReturn(userAccount);
243+
244+
Account account = mock(Account.class);
245+
Mockito.when(account.getAccountName()).thenReturn("account");
246+
Mockito.when(account.getDomainId()).thenReturn(domainId);
247+
Mockito.when(account.getType()).thenReturn(Account.Type.NORMAL);
248+
Mockito.when(account.getType()).thenReturn(Account.Type.NORMAL);
249+
Mockito.when(accountManager.getAccount(200L)).thenReturn(account);
250+
251+
UserVO userVO = mock(UserVO.class);
252+
Mockito.when(userVO.getUuid()).thenReturn("user-uuid");
253+
Mockito.when(accountManager.getActiveUser(100L)).thenReturn(userVO);
254+
255+
Mockito.when(session.getAttributeNames()).thenReturn(Collections.enumeration(List.of(PASSWORD_CHANGE_REQUIRED)));
256+
Mockito.when(session.getAttribute(PASSWORD_CHANGE_REQUIRED)).thenReturn(Boolean.TRUE);
257+
258+
ResponseObject response = apiServer.loginUser(session, username, password, domainId, domainPath, loginIp, requestParams);
259+
Assert.assertNotNull(response);
260+
Assert.assertTrue(response instanceof LoginCmdResponse);
261+
Mockito.verify(session).setAttribute(eq("userid"), eq(100L));
262+
Mockito.verify(session).setAttribute(eq(ApiConstants.SESSIONKEY), anyString());
263+
}
264+
265+
@Test(expected = CloudAuthenticationException.class)
266+
public void testLoginUserDomainNotFound() throws Exception {
267+
Mockito.when(domainManager.findDomainByIdOrPath(anyLong(), anyString())).thenReturn(null);
268+
apiServer.loginUser(session, "user", "pass", 1L, "/", null, null);
269+
}
270+
271+
@Test(expected = CloudAuthenticationException.class)
272+
public void testLoginUserAuthFailed() throws Exception {
273+
DomainVO domain = mock(DomainVO.class);
274+
Mockito.when(domain.getId()).thenReturn(1L);
275+
Mockito.when(domainManager.findDomainByIdOrPath(anyLong(), anyString())).thenReturn(domain);
276+
Mockito.when(accountManager.authenticateUser(anyString(), anyString(), anyLong(), any(), any())).thenReturn(null);
277+
apiServer.loginUser(session, "user", "pass", 1L, "/", null, null);
278+
}
179279
}

0 commit comments

Comments
 (0)