').addClass(this.$element.prop("checked")?this._onstyle:this._offstyle+" off").addClass(b).addClass(this.options.style);this.$element.wrap(g),a.extend(this,{$toggle:this.$element.parent(),$toggleOn:c,$toggleOff:d,$toggleGroup:f}),this.$toggle.append(f);var h=this.options.width||Math.max(c.outerWidth(),d.outerWidth())+e.outerWidth()/2,i=this.options.height||Math.max(c.outerHeight(),d.outerHeight());c.addClass("toggle-on"),d.addClass("toggle-off"),this.$toggle.css({width:h,height:i}),this.options.height&&(c.css("line-height",c.height()+"px"),d.css("line-height",d.height()+"px")),this.update(!0),this.trigger(!0)},c.prototype.toggle=function(){this.$element.prop("checked")?this.off():this.on()},c.prototype.on=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._offstyle+" off").addClass(this._onstyle),this.$element.prop("checked",!0),void(a||this.trigger()))},c.prototype.off=function(a){return this.$element.prop("disabled")?!1:(this.$toggle.removeClass(this._onstyle).addClass(this._offstyle+" off"),this.$element.prop("checked",!1),void(a||this.trigger()))},c.prototype.enable=function(){this.$toggle.removeAttr("disabled"),this.$element.prop("disabled",!1)},c.prototype.disable=function(){this.$toggle.attr("disabled","disabled"),this.$element.prop("disabled",!0)},c.prototype.update=function(a){this.$element.prop("disabled")?this.disable():this.enable(),this.$element.prop("checked")?this.on(a):this.off(a)},c.prototype.trigger=function(b){this.$element.off("change.bs.toggle"),b||this.$element.change(),this.$element.on("change.bs.toggle",a.proxy(function(){this.update()},this))},c.prototype.destroy=function(){this.$element.off("change.bs.toggle"),this.$toggleGroup.remove(),this.$element.removeData("bs.toggle"),this.$element.unwrap()};var d=a.fn.bootstrapToggle;a.fn.bootstrapToggle=b,a.fn.bootstrapToggle.Constructor=c,a.fn.toggle.noConflict=function(){return a.fn.bootstrapToggle=d,this},a(function(){a("input[type=checkbox][data-toggle^=toggle]").bootstrapToggle()}),a(document).on("click.bs.toggle","div[data-toggle^=toggle]",function(b){var c=a(this).find("input[type=checkbox]");c.bootstrapToggle("toggle"),b.preventDefault()})}(jQuery);
9 | //# sourceMappingURL=bootstrap-toggle.min.js.map
--------------------------------------------------------------------------------
/src/main/resources/static/js/custom.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 WTFDYUM
3 | *
4 | * This file is part of the WTFDYUM project.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | $(function() {
19 | $('.option').on('change', function() {
20 | if($(this).is(':checked')) {
21 | window.location.href = "/user/feature/enable/" + $(this).data('name');
22 | } else {
23 | window.location.href = "/user/feature/disable/" + $(this).data('name');
24 | }
25 | });
26 |
27 | $('#more-button').on('click', function() {
28 | $.get("/ajax/recentEvents/" + ($('#events div.alert').length + 1), function(events) {
29 | if(events.trim().length == 0) {
30 | $('#more-button').hide();
31 | }
32 | $('#events').append(events);
33 | });
34 | });
35 | });
36 |
--------------------------------------------------------------------------------
/src/main/resources/templates/admin/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
Why The Fuck Did You Unfollow Me?
11 | Connected as [[${user.name}]] (@[[${user.screenName}]])!
12 |
Admin statistics:
13 | Total members: [[${membersCount}]].
14 | Feature adoption:
15 |
[[${feature.name()}]]: [[${featureEnabledCount[__${feature.name()}__]}]]
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/main/resources/templates/common/template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
25 |
26 |
27 |
28 |
48 |
49 |
50 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/src/main/resources/templates/error.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
Error!
11 |
An unknown error occured while processing your request. Click here to go back to the homepage.
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/main/resources/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
Why The Fuck Did You Unfollow Me?
11 |
Find out who unfollowed you on Twitter!
12 | You will get a direct message everytime someone stops
13 | following you.
14 |
15 | Signin with Twitter now !
16 |
17 |
18 |
19 |
20 |
Unfollowers
21 |
Get a direct message or post a public tweet when someone unfollow you.
22 |
23 |
No unwanted twitter interactions
24 |
We will never interact with twitter for something you did not explicitly asked us for.
25 |
26 |
27 |
Open source
28 |
Don't just trust us when you give us your twitter credentials. Verify what we are exactly doing in the code
29 |
30 |
Host your own instance
31 |
It's open source, so you could just grab the code, build it and host your own instance.
32 |
33 |
34 |

35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/src/main/resources/templates/user/fragment/events.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | :
4 |
5 |
6 | :
7 |
8 |
9 | :
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/main/resources/templates/user/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
9 |
10 |
Why The Fuck Did You Unfollow Me?
11 | Connected as [[${user.name}]] (@[[${user.screenName}]])!
12 |
13 |
14 |
Settings
15 |
16 |
20 |
21 |
22 |
23 |
Your history
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/src/test/java/com/jeanchampemont/wtfdyum/WTFDYUMApplicationTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015 WTFDYUM
3 | *
4 | * This file is part of the WTFDYUM project.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package com.jeanchampemont.wtfdyum;
19 |
20 | import org.junit.Test;
21 | import org.junit.runner.RunWith;
22 | import org.springframework.boot.test.SpringApplicationConfiguration;
23 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
24 | import org.springframework.test.context.web.WebAppConfiguration;
25 |
26 | @RunWith(SpringJUnit4ClassRunner.class)
27 | @SpringApplicationConfiguration(classes = WTFDYUMApplication.class)
28 | @WebAppConfiguration
29 | public class WTFDYUMApplicationTests {
30 |
31 | @Test
32 | public void contextLoads() {
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/test/java/com/jeanchampemont/wtfdyum/security/SecurityAspectTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015, 2016 WTFDYUM
3 | *
4 | * This file is part of the WTFDYUM project.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package com.jeanchampemont.wtfdyum.security;
19 |
20 | import com.jeanchampemont.wtfdyum.service.AuthenticationService;
21 | import org.aspectj.lang.ProceedingJoinPoint;
22 | import org.assertj.core.api.Assertions;
23 | import org.junit.Test;
24 | import org.junit.runner.RunWith;
25 | import org.mockito.InjectMocks;
26 | import org.mockito.Mock;
27 | import org.mockito.runners.MockitoJUnitRunner;
28 |
29 | import java.lang.annotation.Annotation;
30 |
31 | import static org.mockito.Mockito.*;
32 |
33 | @RunWith(MockitoJUnitRunner.class)
34 | public class SecurityAspectTest {
35 |
36 | @Mock
37 | private AuthenticationService authenticationService;
38 |
39 | @Mock
40 | private ProceedingJoinPoint pjp;
41 |
42 | @InjectMocks
43 | private SecurityAspect sut;
44 |
45 | @Test
46 | public void aroundSecuredMethodTestAuthorized() throws Throwable {
47 | final Object expectedResult = new Object();
48 |
49 | when(authenticationService.isAuthenticated()).thenReturn(true);
50 | when(pjp.proceed()).thenReturn(expectedResult);
51 |
52 | final Object result = sut.aroundSecuredMethod(pjp, new Secured() {
53 | @Override
54 | public Class extends Annotation> annotationType() {
55 | return null;
56 | }
57 | });
58 |
59 | Assertions.assertThat(result).isSameAs(expectedResult);
60 | verify(pjp, times(1)).proceed();
61 | }
62 |
63 | @Test(expected = SecurityException.class)
64 | public void aroundSecuredMethodTestUnauthorized() throws Throwable {
65 | when(authenticationService.isAuthenticated()).thenReturn(false);
66 |
67 | sut.aroundSecuredMethod(pjp, new Secured() {
68 | @Override
69 | public Class extends Annotation> annotationType() {
70 | // TODO Auto-generated method stub
71 | return null;
72 | }
73 | });
74 |
75 | Assertions.failBecauseExceptionWasNotThrown(SecurityException.class);
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/test/java/com/jeanchampemont/wtfdyum/service/AdminServiceTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2018 WTFDYUM
3 | *
4 | * This file is part of the WTFDYUM project.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package com.jeanchampemont.wtfdyum.service;
19 |
20 | import com.jeanchampemont.wtfdyum.WTFDYUMApplication;
21 | import com.jeanchampemont.wtfdyum.dto.Feature;
22 | import com.jeanchampemont.wtfdyum.service.impl.AdminServiceImpl;
23 | import org.junit.Before;
24 | import org.junit.Test;
25 | import org.junit.runner.RunWith;
26 | import org.mockito.Mock;
27 | import org.springframework.boot.test.SpringApplicationConfiguration;
28 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
29 |
30 | import java.util.Arrays;
31 | import java.util.HashSet;
32 | import java.util.Map;
33 | import java.util.Set;
34 |
35 | import static org.assertj.core.api.Assertions.assertThat;
36 | import static org.mockito.Mockito.when;
37 | import static org.mockito.MockitoAnnotations.initMocks;
38 |
39 | @RunWith(SpringJUnit4ClassRunner.class)
40 | @SpringApplicationConfiguration(classes = WTFDYUMApplication.class)
41 | public class AdminServiceTest {
42 | @Mock
43 | private FeatureService featureService;
44 |
45 | private AdminService sut;
46 |
47 | @Before
48 | public void init() {
49 | initMocks(this);
50 | sut = new AdminServiceImpl(featureService);
51 | }
52 |
53 | @Test
54 | public void countEnabledFeatureNominalTest() {
55 | Set
ids = new HashSet<>(Arrays.asList(42L, 45L));
56 | when(featureService.isEnabled(42L, Feature.NOTIFY_UNFOLLOW)).thenReturn(true);
57 | when(featureService.isEnabled(45L, Feature.NOTIFY_UNFOLLOW)).thenReturn(true);
58 | when(featureService.isEnabled(42L, Feature.TWEET_UNFOLLOW)).thenReturn(true);
59 | when(featureService.isEnabled(45L, Feature.TWEET_UNFOLLOW)).thenReturn(false);
60 |
61 | Map result = sut.countEnabledFeature(ids);
62 |
63 | assertThat(result).isNotNull();
64 | assertThat(result).hasSize(2);
65 | assertThat(result).containsKeys(Feature.NOTIFY_UNFOLLOW, Feature.TWEET_UNFOLLOW);
66 | assertThat(result.get(Feature.NOTIFY_UNFOLLOW)).isEqualTo(2);
67 | assertThat(result.get(Feature.TWEET_UNFOLLOW)).isEqualTo(1);
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/test/java/com/jeanchampemont/wtfdyum/service/AuthenticationServiceTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015, 2016, 2018 WTFDYUM
3 | *
4 | * This file is part of the WTFDYUM project.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package com.jeanchampemont.wtfdyum.service;
19 |
20 | import com.jeanchampemont.wtfdyum.WTFDYUMApplication;
21 | import com.jeanchampemont.wtfdyum.dto.Principal;
22 | import com.jeanchampemont.wtfdyum.service.impl.SessionAuthenticationServiceImpl;
23 | import com.jeanchampemont.wtfdyum.utils.SessionProvider;
24 | import org.junit.Before;
25 | import org.junit.Test;
26 | import org.junit.runner.RunWith;
27 | import org.mockito.Mock;
28 | import org.springframework.boot.test.SpringApplicationConfiguration;
29 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
30 |
31 | import javax.servlet.http.HttpSession;
32 |
33 | import static org.assertj.core.api.Assertions.assertThat;
34 | import static org.mockito.Matchers.anyString;
35 | import static org.mockito.Matchers.eq;
36 | import static org.mockito.Mockito.*;
37 | import static org.mockito.MockitoAnnotations.initMocks;
38 |
39 | @RunWith(SpringJUnit4ClassRunner.class)
40 | @SpringApplicationConfiguration(classes = WTFDYUMApplication.class)
41 | public class AuthenticationServiceTest {
42 |
43 | @Mock
44 | private HttpSession session;
45 |
46 | @Mock
47 | private SessionProvider sessionProvider;
48 |
49 | private AuthenticationService sut;
50 |
51 | @Before
52 | public void ainit() {
53 | initMocks(this);
54 | when(sessionProvider.getSession()).thenReturn(session);
55 | sut = new SessionAuthenticationServiceImpl(sessionProvider, 42L);
56 | }
57 |
58 | @Test(expected = NullPointerException.class)
59 | public void authenticateNullUserIdTest() {
60 | sut.authenticate(new Principal(null, "toke", "secrt"));
61 | }
62 |
63 | @Test(expected = NullPointerException.class)
64 | public void authenticateNullUserTest() {
65 | sut.authenticate(null);
66 | }
67 |
68 | @Test
69 | public void authenticateTest() {
70 | sut.authenticate(new Principal(120L, "tok", "secret"));
71 |
72 | verify(session, times(1)).setAttribute(anyString(), eq(120L));
73 | }
74 |
75 | @Test
76 | public void getCurrentUserIdAuthenticatedTest() {
77 | when(session.getAttribute(anyString())).thenReturn(144L);
78 | final Long currentUserId = sut.getCurrentUserId();
79 |
80 | assertThat(currentUserId).isNotNull();
81 | assertThat(currentUserId).isEqualTo(144L);
82 | }
83 |
84 | @Test
85 | public void getCurrentUserIdNotAuthenticatedTest() {
86 | when(session.getAttribute(anyString())).thenReturn(null);
87 | final Long currentUserId = sut.getCurrentUserId();
88 |
89 | assertThat(currentUserId).isNull();
90 | }
91 |
92 | @Test
93 | public void isAdminNominalTest() {
94 | when(session.getAttribute(anyString())).thenReturn(42L);
95 | Boolean isAdmin = sut.isAdmin();
96 |
97 | assertThat(isAdmin).isNotNull();
98 | assertThat(isAdmin).isTrue();
99 | }
100 |
101 | @Test
102 | public void isAdminNotAdminTest() {
103 | when(session.getAttribute(anyString())).thenReturn(43L);
104 | Boolean isAdmin = sut.isAdmin();
105 |
106 | assertThat(isAdmin).isNotNull();
107 | assertThat(isAdmin).isFalse();
108 | }
109 |
110 | @Test
111 | public void isAuthenticatedAuthenticatedTest() {
112 | when(session.getAttribute(anyString())).thenReturn(144L);
113 | final Boolean isAuthenticated = sut.isAuthenticated();
114 |
115 | assertThat(isAuthenticated).isNotNull();
116 | assertThat(isAuthenticated).isTrue();
117 | }
118 |
119 | @Test
120 | public void isAuthenticatedNotAuthenticatedTest() {
121 | when(session.getAttribute(anyString())).thenReturn(null);
122 | final Boolean isAuthenticated = sut.isAuthenticated();
123 |
124 | assertThat(isAuthenticated).isNotNull();
125 | assertThat(isAuthenticated).isFalse();
126 | }
127 |
128 | @Test
129 | public void logOutTest() {
130 | sut.logOut();
131 | verify(session, times(1)).removeAttribute(anyString());
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/src/test/java/com/jeanchampemont/wtfdyum/service/CronServiceTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015, 2016 WTFDYUM
3 | *
4 | * This file is part of the WTFDYUM project.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package com.jeanchampemont.wtfdyum.service;
19 |
20 | import com.jeanchampemont.wtfdyum.WTFDYUMApplication;
21 | import com.jeanchampemont.wtfdyum.dto.Event;
22 | import com.jeanchampemont.wtfdyum.dto.Feature;
23 | import com.jeanchampemont.wtfdyum.dto.Principal;
24 | import com.jeanchampemont.wtfdyum.dto.type.EventType;
25 | import com.jeanchampemont.wtfdyum.dto.type.UserLimitType;
26 | import com.jeanchampemont.wtfdyum.service.impl.CronServiceImpl;
27 | import com.jeanchampemont.wtfdyum.utils.WTFDYUMException;
28 | import com.jeanchampemont.wtfdyum.utils.WTFDYUMExceptionType;
29 | import org.junit.Before;
30 | import org.junit.Test;
31 | import org.junit.runner.RunWith;
32 | import org.mockito.Mock;
33 | import org.springframework.boot.test.SpringApplicationConfiguration;
34 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
35 |
36 | import java.util.Arrays;
37 | import java.util.HashSet;
38 |
39 | import static org.mockito.Mockito.*;
40 | import static org.mockito.MockitoAnnotations.initMocks;
41 |
42 | @RunWith(SpringJUnit4ClassRunner.class)
43 | @SpringApplicationConfiguration(classes = WTFDYUMApplication.class)
44 | public class CronServiceTest {
45 |
46 | @Mock
47 | private PrincipalService principalService;
48 |
49 | @Mock
50 | private UserService userService;
51 |
52 | @Mock
53 | private TwitterService twitterService;
54 |
55 | @Mock
56 | private FeatureService featureService;
57 |
58 | private CronService sut;
59 |
60 | @Before
61 | public void _init() {
62 | initMocks(this);
63 | sut = new CronServiceImpl(principalService, userService, twitterService, featureService);
64 | }
65 |
66 | @Test
67 | public void checkCredentialsTest() throws Exception {
68 | final Principal principal = principal(1L);
69 | when(twitterService.verifyCredentials(principal)).thenReturn(true);
70 |
71 | sut.checkCredentials();
72 | verify(userService, times(1)).resetLimit(1L, UserLimitType.CREDENTIALS_INVALID);
73 | }
74 |
75 | @Test
76 | public void checkCredentialsTestInvalid() throws Exception {
77 | final Principal principal = principal(1L);
78 | when(twitterService.verifyCredentials(principal)).thenReturn(false);
79 |
80 | sut.checkCredentials();
81 |
82 | verify(userService, times(1)).addEvent(1L, new Event(EventType.INVALID_TWITTER_CREDENTIALS, ""));
83 | verify(userService, times(1)).applyLimit(1L, UserLimitType.CREDENTIALS_INVALID);
84 | }
85 |
86 | @Test
87 | public void cronTestDisabled() throws Exception {
88 | principal(5L);
89 | featureEnabled(5L, true, Feature.NOTIFY_UNFOLLOW);
90 |
91 | sut.cron();
92 | }
93 |
94 | @Test
95 | public void cronTestEvents() throws Exception {
96 | principal(12L);
97 | featureEnabled(12L, true, Feature.NOTIFY_UNFOLLOW, Feature.TWEET_UNFOLLOW);
98 |
99 | when(featureService.cron(12L, Feature.NOTIFY_UNFOLLOW))
100 | .thenReturn(new HashSet<>(Arrays.asList(new Event(EventType.UNFOLLOW, "toto"))));
101 | when(featureService.cron(12L, Feature.TWEET_UNFOLLOW))
102 | .thenReturn(new HashSet<>(Arrays.asList(new Event(EventType.UNFOLLOW, "toto"))));
103 |
104 | sut.cron();
105 |
106 | verify(featureService, times(1)).cron(12L, Feature.NOTIFY_UNFOLLOW);
107 | verify(featureService, times(1)).cron(12L, Feature.TWEET_UNFOLLOW);
108 | verify(featureService, times(1)).completeCron(12L, Feature.NOTIFY_UNFOLLOW);
109 | verify(featureService, times(1)).completeCron(12L, Feature.TWEET_UNFOLLOW);
110 |
111 | verify(userService, times(1)).addEvent(12L, new Event(EventType.UNFOLLOW, "toto"));
112 | }
113 |
114 | @Test
115 | public void cronTestNominal() throws Exception {
116 | principal(1L);
117 | featureEnabled(1L, true, Feature.NOTIFY_UNFOLLOW);
118 |
119 | sut.cron();
120 |
121 | verify(featureService, times(1)).cron(1L, Feature.NOTIFY_UNFOLLOW);
122 | verify(featureService, times(1)).completeCron(1L, Feature.NOTIFY_UNFOLLOW);
123 | }
124 |
125 | @Test
126 | public void cronTestNPEError() throws Exception {
127 | principal(4L);
128 | featureEnabled(4L, true, Feature.NOTIFY_UNFOLLOW);
129 |
130 | when(featureService.cron(4L, Feature.NOTIFY_UNFOLLOW)).thenThrow(new NullPointerException());
131 |
132 | sut.cron();
133 |
134 | // should have an event UNKNOWN_ERROR
135 | verify(userService, times(1)).addEvent(4L, new Event(EventType.UNKNOWN_ERROR, null));
136 | }
137 |
138 | @Test
139 | public void cronTestRateLimitError() throws Exception {
140 |
141 | principal(3L);
142 | featureEnabled(3L, true, Feature.NOTIFY_UNFOLLOW);
143 |
144 | when(featureService.cron(3L, Feature.NOTIFY_UNFOLLOW)).thenThrow(new WTFDYUMException(WTFDYUMExceptionType.GET_FOLLOWERS_RATE_LIMIT_EXCEEDED));
145 |
146 | sut.cron();
147 |
148 | // should have an event RATE_LIMIT_EXCEEDED
149 | verify(userService, times(1)).addEvent(3L, new Event(EventType.RATE_LIMIT_EXCEEDED, null));
150 | }
151 |
152 | @Test
153 | public void cronTestTwitterError() throws Exception {
154 | principal(2L);
155 | featureEnabled(2L, true, Feature.NOTIFY_UNFOLLOW);
156 |
157 | when(featureService.cron(2L, Feature.NOTIFY_UNFOLLOW)).thenThrow(new WTFDYUMException(WTFDYUMExceptionType.TWITTER_ERROR));
158 |
159 | sut.cron();
160 |
161 | // should have an event TWITTER_ERROR
162 | verify(userService, times(1)).addEvent(2L, new Event(EventType.TWITTER_ERROR, null));
163 | }
164 |
165 | private void featureEnabled(final long userId, final boolean value, final Feature... feature) {
166 | when(userService.getEnabledFeatures(userId)).thenReturn(new HashSet<>(Arrays.asList(feature)));
167 | }
168 |
169 | private Principal principal(final long id) {
170 | when(principalService.getMembers()).thenReturn(new HashSet<>(Arrays.asList(id)));
171 | final Principal principal = new Principal(id, "Principal 1 Token", "Principal 1 Token Secret");
172 | when(principalService.get(id)).thenReturn(principal);
173 | return principal;
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/src/test/java/com/jeanchampemont/wtfdyum/service/FeatureServiceTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 WTFDYUM
3 | *
4 | * This file is part of the WTFDYUM project.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package com.jeanchampemont.wtfdyum.service;
19 |
20 | import com.jeanchampemont.wtfdyum.WTFDYUMApplication;
21 | import com.jeanchampemont.wtfdyum.dto.Event;
22 | import com.jeanchampemont.wtfdyum.dto.Feature;
23 | import com.jeanchampemont.wtfdyum.service.feature.FeatureStrategy;
24 | import com.jeanchampemont.wtfdyum.service.feature.impl.NotifyUnfollowFeatureStrategy;
25 | import com.jeanchampemont.wtfdyum.service.impl.FeatureServiceImpl;
26 | import com.jeanchampemont.wtfdyum.utils.WTFDYUMException;
27 | import org.junit.Before;
28 | import org.junit.Test;
29 | import org.junit.runner.RunWith;
30 | import org.mockito.Mock;
31 | import org.springframework.boot.test.SpringApplicationConfiguration;
32 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
33 |
34 | import java.util.HashMap;
35 | import java.util.HashSet;
36 | import java.util.Map;
37 | import java.util.Set;
38 |
39 | import static org.assertj.core.api.Assertions.assertThat;
40 | import static org.mockito.Mockito.*;
41 | import static org.mockito.MockitoAnnotations.initMocks;
42 |
43 | @RunWith(SpringJUnit4ClassRunner.class)
44 | @SpringApplicationConfiguration(classes = WTFDYUMApplication.class)
45 | public class FeatureServiceTest {
46 |
47 | @Mock
48 | NotifyUnfollowFeatureStrategy notifyUnfollowFeatureService;
49 |
50 | private FeatureService sut;
51 |
52 | @Before
53 | public void _init() {
54 | initMocks(this);
55 | final Map featureServices = new HashMap<>();
56 | featureServices.put(Feature.NOTIFY_UNFOLLOW, notifyUnfollowFeatureService);
57 | sut = new FeatureServiceImpl(featureServices);
58 | }
59 |
60 | @Test
61 | public void completeCronTest() throws WTFDYUMException {
62 | sut.completeCron(123L, Feature.NOTIFY_UNFOLLOW);
63 |
64 | verify(notifyUnfollowFeatureService, times(1)).completeCron(123L);
65 | }
66 |
67 | @Test
68 | public void cronTest() throws WTFDYUMException {
69 | final Set expectedResult = new HashSet<>();
70 | when(notifyUnfollowFeatureService.cron(123L)).thenReturn(expectedResult);
71 |
72 | final Set result = sut.cron(123L, Feature.NOTIFY_UNFOLLOW);
73 |
74 | verify(notifyUnfollowFeatureService, times(1)).cron(123L);
75 |
76 | assertThat(result).isSameAs(expectedResult);
77 | }
78 |
79 | @Test
80 | public void disableFeatureTest() {
81 | when(notifyUnfollowFeatureService.disableFeature(123L)).thenReturn(false);
82 |
83 | final boolean result = sut.disableFeature(123L, Feature.NOTIFY_UNFOLLOW);
84 |
85 | verify(notifyUnfollowFeatureService, times(1)).disableFeature(123L);
86 |
87 | assertThat(result).isFalse();
88 | }
89 |
90 | @Test
91 | public void enableFeatureTest() {
92 | when(notifyUnfollowFeatureService.enableFeature(123L)).thenReturn(true);
93 |
94 | final boolean result = sut.enableFeature(123L, Feature.NOTIFY_UNFOLLOW);
95 |
96 | verify(notifyUnfollowFeatureService, times(1)).enableFeature(123L);
97 |
98 | assertThat(result).isTrue();
99 | }
100 |
101 | @Test
102 | public void isEnabledTest() {
103 | when(notifyUnfollowFeatureService.isEnabled(123L)).thenReturn(true);
104 |
105 | final boolean result = sut.isEnabled(123L, Feature.NOTIFY_UNFOLLOW);
106 |
107 | verify(notifyUnfollowFeatureService, times(1)).isEnabled(123L);
108 |
109 | assertThat(result).isTrue();
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/test/java/com/jeanchampemont/wtfdyum/service/FollowersServiceTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015, 2016 WTFDYUM
3 | *
4 | * This file is part of the WTFDYUM project.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package com.jeanchampemont.wtfdyum.service;
19 |
20 | import com.jeanchampemont.wtfdyum.WTFDYUMApplication;
21 | import com.jeanchampemont.wtfdyum.service.impl.FollowersServiceImpl;
22 | import org.junit.Before;
23 | import org.junit.Test;
24 | import org.junit.runner.RunWith;
25 | import org.mockito.Mock;
26 | import org.springframework.boot.test.SpringApplicationConfiguration;
27 | import org.springframework.data.redis.core.RedisTemplate;
28 | import org.springframework.data.redis.core.SetOperations;
29 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
30 |
31 | import java.util.Arrays;
32 | import java.util.HashSet;
33 | import java.util.Set;
34 |
35 | import static org.assertj.core.api.Assertions.assertThat;
36 | import static org.mockito.Mockito.*;
37 | import static org.mockito.MockitoAnnotations.initMocks;
38 |
39 | @RunWith(SpringJUnit4ClassRunner.class)
40 | @SpringApplicationConfiguration(classes = WTFDYUMApplication.class)
41 | public class FollowersServiceTest {
42 |
43 | private FollowersServiceImpl sut;
44 |
45 | @Mock
46 | private RedisTemplate longRedisTemplate;
47 |
48 | @Mock
49 | private SetOperations longSetOperations;
50 |
51 | @Before
52 | public void _init() {
53 | initMocks(this);
54 | sut = new FollowersServiceImpl(longRedisTemplate);
55 | }
56 |
57 | @Test
58 | public void getUnfollowersTest() {
59 | final Set result = new HashSet<>(Arrays.asList(124L, 901L, 44L));
60 |
61 | when(longRedisTemplate.opsForSet()).thenReturn(longSetOperations);
62 | when(longSetOperations.difference("FOLLOWERS_12", "TEMP_FOLLOWERS_12")).thenReturn(result);
63 |
64 | final Set currentFollowersId = new HashSet<>(Arrays.asList(999L, 998L, 997L, 978L));
65 |
66 | final Set returnedResult = sut.getUnfollowers(12L, currentFollowersId);
67 |
68 | verify(longSetOperations).add("TEMP_FOLLOWERS_12", 978L, 997L, 998L, 999L);
69 | verify(longRedisTemplate).delete("TEMP_FOLLOWERS_12");
70 |
71 | assertThat(returnedResult).isNotNull();
72 | assertThat(returnedResult).isEqualTo(result);
73 | }
74 |
75 | @Test
76 | public void saveFollowersTest() {
77 | when(longRedisTemplate.opsForSet()).thenReturn(longSetOperations);
78 |
79 | sut.saveFollowers(1788L, new HashSet(Arrays.asList(888L, 89L, 19L)));
80 |
81 | verify(longRedisTemplate, times(1)).delete("FOLLOWERS_1788");
82 | verify(longSetOperations, times(1)).add("FOLLOWERS_1788", 19L, 888L, 89L);
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/src/test/java/com/jeanchampemont/wtfdyum/service/PrincipalServiceTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015, 2016 WTFDYUM
3 | *
4 | * This file is part of the WTFDYUM project.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package com.jeanchampemont.wtfdyum.service;
19 |
20 | import com.jeanchampemont.wtfdyum.WTFDYUMApplication;
21 | import com.jeanchampemont.wtfdyum.dto.Principal;
22 | import com.jeanchampemont.wtfdyum.service.impl.PrincipalServiceImpl;
23 | import org.junit.Before;
24 | import org.junit.Test;
25 | import org.junit.runner.RunWith;
26 | import org.mockito.Mock;
27 | import org.springframework.boot.test.SpringApplicationConfiguration;
28 | import org.springframework.data.redis.core.RedisTemplate;
29 | import org.springframework.data.redis.core.SetOperations;
30 | import org.springframework.data.redis.core.ValueOperations;
31 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
32 |
33 | import java.util.Arrays;
34 | import java.util.HashSet;
35 | import java.util.Set;
36 |
37 | import static org.assertj.core.api.Assertions.assertThat;
38 | import static org.mockito.Mockito.*;
39 | import static org.mockito.MockitoAnnotations.initMocks;
40 |
41 | @RunWith(SpringJUnit4ClassRunner.class)
42 | @SpringApplicationConfiguration(classes = WTFDYUMApplication.class)
43 | public class PrincipalServiceTest {
44 |
45 | private PrincipalService sut;
46 |
47 | @Mock
48 | private RedisTemplate longRedisTemplate;
49 |
50 | @Mock
51 | private RedisTemplate principalRedisTemplate;
52 |
53 | @Mock
54 | private ValueOperations valueOperations;
55 |
56 | @Mock
57 | private SetOperations setOperations;
58 |
59 | @Before
60 | public void ainit() {
61 | initMocks(this);
62 | sut = new PrincipalServiceImpl(principalRedisTemplate, longRedisTemplate);
63 | }
64 |
65 | @Test
66 | public void countMembersTest() {
67 | when(longRedisTemplate.opsForSet()).thenReturn(setOperations);
68 | when(setOperations.size("MEMBERS")).thenReturn(133L);
69 |
70 | final int result = sut.countMembers();
71 |
72 | assertThat(result).isEqualTo(133);
73 | }
74 |
75 | @Test
76 | public void getMembersTest() {
77 | when(longRedisTemplate.opsForSet()).thenReturn(setOperations);
78 | when(setOperations.members("MEMBERS")).thenReturn(new HashSet(Arrays.asList(12L, 13L, 190L)));
79 |
80 | final Set members = sut.getMembers();
81 |
82 | assertThat(members).isNotNull();
83 | assertThat(members.size()).isEqualTo(3);
84 | assertThat(members.contains(12L)).isTrue();
85 | assertThat(members.contains(13L)).isTrue();
86 | assertThat(members.contains(190L)).isTrue();
87 | }
88 |
89 | @Test
90 | public void getTest() {
91 | final Principal u = new Principal(12L, "tokdf", "secrrr");
92 |
93 | when(principalRedisTemplate.opsForValue()).thenReturn(valueOperations);
94 | when(valueOperations.get("190")).thenReturn(u);
95 |
96 | final Principal principal = sut.get(190L);
97 |
98 | assertThat(principal).isNotNull();
99 | assertThat(principal).isEqualTo(u);
100 | }
101 |
102 | @Test(expected = NullPointerException.class)
103 | public void getTestNullId() {
104 | sut.get(null);
105 | }
106 |
107 | @Test(expected = NullPointerException.class)
108 | public void saveUpdateNullUserIdTest() {
109 | sut.saveUpdate(new Principal(null, "lkdf", "sec"));
110 | }
111 |
112 | @Test(expected = NullPointerException.class)
113 | public void saveUpdateNullUserTest() {
114 | sut.saveUpdate(null);
115 | }
116 |
117 | @Test
118 | public void saveUpdateTest() {
119 | final Principal u = new Principal(12L, "tokdf", "secrrr");
120 |
121 | when(principalRedisTemplate.opsForValue()).thenReturn(valueOperations);
122 | when(longRedisTemplate.opsForSet()).thenReturn(setOperations);
123 |
124 | sut.saveUpdate(u);
125 |
126 | verify(valueOperations, times(1)).set("12", u);
127 | verify(setOperations, times(1)).add("MEMBERS", 12L);
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/src/test/java/com/jeanchampemont/wtfdyum/service/UserServiceTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015, 2016 WTFDYUM
3 | *
4 | * This file is part of the WTFDYUM project.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package com.jeanchampemont.wtfdyum.service;
19 |
20 | import com.jeanchampemont.wtfdyum.WTFDYUMApplication;
21 | import com.jeanchampemont.wtfdyum.dto.Event;
22 | import com.jeanchampemont.wtfdyum.dto.Feature;
23 | import com.jeanchampemont.wtfdyum.dto.type.EventType;
24 | import com.jeanchampemont.wtfdyum.dto.type.UserLimitType;
25 | import com.jeanchampemont.wtfdyum.service.impl.UserServiceImpl;
26 | import org.junit.Before;
27 | import org.junit.Test;
28 | import org.junit.runner.RunWith;
29 | import org.mockito.ArgumentCaptor;
30 | import org.mockito.Mock;
31 | import org.springframework.boot.test.SpringApplicationConfiguration;
32 | import org.springframework.data.redis.core.ListOperations;
33 | import org.springframework.data.redis.core.RedisTemplate;
34 | import org.springframework.data.redis.core.SetOperations;
35 | import org.springframework.data.redis.core.ValueOperations;
36 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
37 |
38 | import java.time.Clock;
39 | import java.time.Instant;
40 | import java.time.LocalDateTime;
41 | import java.time.ZoneId;
42 | import java.util.Arrays;
43 | import java.util.HashSet;
44 | import java.util.List;
45 | import java.util.Set;
46 |
47 | import static org.assertj.core.api.Assertions.assertThat;
48 | import static org.mockito.Matchers.eq;
49 | import static org.mockito.Mockito.*;
50 | import static org.mockito.MockitoAnnotations.initMocks;
51 |
52 | @RunWith(SpringJUnit4ClassRunner.class)
53 | @SpringApplicationConfiguration(classes = WTFDYUMApplication.class)
54 | public class UserServiceTest {
55 |
56 | private UserService sut;
57 |
58 | @Mock
59 | private RedisTemplate longRedisTemplate;
60 |
61 | @Mock
62 | private RedisTemplate eventRedisTemplate;
63 |
64 | @Mock
65 | private RedisTemplate featureRedisTemplate;
66 |
67 | @Mock
68 | private SetOperations longSetOperations;
69 |
70 | @Mock
71 | private ValueOperations longValueOperations;
72 |
73 | @Mock
74 | private SetOperations featureSetOperations;
75 |
76 | @Mock
77 | private ListOperations eventListOperations;
78 |
79 | @Mock
80 | private FeatureService featureService;
81 |
82 | private final Clock clock = Clock.fixed(Instant.parse("2007-12-03T10:15:30.00Z"), ZoneId.of("Z"));
83 |
84 | @Before
85 | public void _init() {
86 | initMocks(this);
87 | sut = new UserServiceImpl(eventRedisTemplate, featureRedisTemplate, longRedisTemplate, featureService, clock);
88 | }
89 |
90 | @Test
91 | public void addEventTest() {
92 | when(eventRedisTemplate.opsForList()).thenReturn(eventListOperations);
93 |
94 | final Event event = new Event(EventType.REGISTRATION, "data");
95 |
96 | sut.addEvent(31L, event);
97 |
98 | verify(eventListOperations, times(1)).leftPush("EVENTS_31", event);
99 | assertThat(event.getCreationDateTime()).isEqualTo(LocalDateTime.now(clock));
100 | }
101 |
102 | @Test
103 | public void applyLimitTestNotReached() {
104 | when(longRedisTemplate.opsForValue()).thenReturn(longValueOperations);
105 | when(longValueOperations.increment(UserLimitType.CREDENTIALS_INVALID.name() + "_442", 1)).thenReturn(4L);
106 |
107 | final boolean result = sut.applyLimit(442L, UserLimitType.CREDENTIALS_INVALID);
108 |
109 | assertThat(result).isFalse();
110 | }
111 |
112 | @Test
113 | public void applyLimitTestReached() {
114 | when(longRedisTemplate.opsForValue()).thenReturn(longValueOperations);
115 | when(eventRedisTemplate.opsForList()).thenReturn(eventListOperations);
116 | when(longValueOperations.increment(UserLimitType.CREDENTIALS_INVALID.name() + "_442", 1)).thenReturn(5L);
117 |
118 | final boolean result = sut.applyLimit(442L, UserLimitType.CREDENTIALS_INVALID);
119 |
120 | assertThat(result).isTrue();
121 | for (final Feature f : Feature.values()) {
122 | verify(featureService, times(1)).disableFeature(442L, f);
123 | }
124 | final ArgumentCaptor eventCaptor = ArgumentCaptor.forClass(Event.class);
125 | verify(eventListOperations, times(1)).leftPush(eq("EVENTS_442"), eventCaptor.capture());
126 | assertThat(eventCaptor.getValue().getType()).isEqualTo(EventType.CREDENTIALS_INVALID_LIMIT_REACHED);
127 | assertThat(eventCaptor.getValue().getAdditionalData()).isEmpty();
128 | assertThat(eventCaptor.getValue().getCreationDateTime()).isEqualTo(LocalDateTime.now(clock));
129 | }
130 |
131 | @Test
132 | public void getEnabledFeaturesTest() {
133 | when(featureRedisTemplate.opsForSet()).thenReturn(featureSetOperations);
134 | when(featureSetOperations.members("FEATURES_1234")).thenReturn(new HashSet<>(Arrays.asList(Feature.NOTIFY_UNFOLLOW, Feature.TWEET_UNFOLLOW)));
135 |
136 | final Set result = sut.getEnabledFeatures(1234L);
137 |
138 | assertThat(result).isEqualTo(new HashSet<>(Arrays.asList(Feature.NOTIFY_UNFOLLOW, Feature.TWEET_UNFOLLOW)));
139 | }
140 |
141 | @Test
142 | public void getRecentEventsTest() {
143 | final List result = Arrays.asList(new Event(EventType.REGISTRATION, "reg"),
144 | new Event(EventType.UNFOLLOW, "unfoll"));
145 |
146 | when(eventRedisTemplate.opsForList()).thenReturn(eventListOperations);
147 | when(eventListOperations.range("EVENTS_1249", 0, 12)).thenReturn(result);
148 |
149 | final List returnedResult = sut.getRecentEvents(1249L, 12);
150 |
151 | assertThat(returnedResult).isNotNull();
152 | assertThat(returnedResult.size()).isEqualTo(2);
153 | assertThat(returnedResult).isEqualTo(result);
154 | }
155 |
156 | @Test
157 | public void getRecentEventsWithStartTest() {
158 | final List result = Arrays.asList(new Event(EventType.REGISTRATION, "reg"),
159 | new Event(EventType.UNFOLLOW, "unfoll"));
160 |
161 | when(eventRedisTemplate.opsForList()).thenReturn(eventListOperations);
162 | when(eventListOperations.range("EVENTS_1249", 10, 15)).thenReturn(result);
163 |
164 | final List returnedResult = sut.getRecentEvents(1249L, 5, 10);
165 |
166 | assertThat(returnedResult).isNotNull();
167 | assertThat(returnedResult.size()).isEqualTo(2);
168 | assertThat(returnedResult).isEqualTo(result);
169 | }
170 |
171 | @Test
172 | public void resetLimitTest() {
173 |
174 | sut.resetLimit(199L, UserLimitType.CREDENTIALS_INVALID);
175 |
176 | verify(longRedisTemplate, times(1)).delete(UserLimitType.CREDENTIALS_INVALID.name() + "_199");
177 | }
178 | }
179 |
--------------------------------------------------------------------------------
/src/test/java/com/jeanchampemont/wtfdyum/service/feature/AbstractFeatureStrategyTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015, 2016 WTFDYUM
3 | *
4 | * This file is part of the WTFDYUM project.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package com.jeanchampemont.wtfdyum.service.feature;
19 |
20 | import com.jeanchampemont.wtfdyum.WTFDYUMApplication;
21 | import com.jeanchampemont.wtfdyum.dto.Feature;
22 | import com.jeanchampemont.wtfdyum.dto.Principal;
23 | import com.jeanchampemont.wtfdyum.dto.User;
24 | import com.jeanchampemont.wtfdyum.service.FollowersService;
25 | import com.jeanchampemont.wtfdyum.service.PrincipalService;
26 | import com.jeanchampemont.wtfdyum.service.TwitterService;
27 | import com.jeanchampemont.wtfdyum.service.feature.impl.AbstractFeatureStrategy;
28 | import com.jeanchampemont.wtfdyum.utils.WTFDYUMException;
29 | import org.junit.Test;
30 | import org.junit.runner.RunWith;
31 | import org.mockito.stubbing.OngoingStubbing;
32 | import org.springframework.boot.test.SpringApplicationConfiguration;
33 | import org.springframework.data.redis.core.RedisTemplate;
34 | import org.springframework.data.redis.core.SetOperations;
35 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
36 |
37 | import java.util.*;
38 | import java.util.function.BiConsumer;
39 |
40 | import static org.assertj.core.api.Assertions.assertThat;
41 | import static org.mockito.Mockito.*;
42 |
43 | @RunWith(SpringJUnit4ClassRunner.class)
44 | @SpringApplicationConfiguration(classes = WTFDYUMApplication.class)
45 | public abstract class AbstractFeatureStrategyTest {
46 |
47 | protected static final String TWEET_TEXT = "@%s tweet";
48 |
49 | protected static final String DM_TEXT = "@%s DM";
50 |
51 | protected PrincipalService principalService;
52 |
53 | protected FollowersService followersService;
54 |
55 | protected TwitterService twitterService;
56 |
57 | protected AbstractFeatureStrategy sut;
58 |
59 | protected RedisTemplate featureRedisTemplate;
60 |
61 | protected SetOperations featureSetOperations;
62 |
63 | @Test
64 | public void disableFeatureTestDisabledFeature() {
65 | when(featureRedisTemplate.opsForSet()).thenReturn(featureSetOperations);
66 | when(featureSetOperations.remove("FEATURES_1334", sut.getFeature())).thenReturn(0L);
67 |
68 | final boolean result = sut.disableFeature(1334L);
69 |
70 | verify(featureSetOperations, times(1)).remove("FEATURES_1334", sut.getFeature());
71 |
72 | assertThat(result).isFalse();
73 | }
74 |
75 | @Test
76 | public void disableFeatureTestEnabledFeature() {
77 | when(featureRedisTemplate.opsForSet()).thenReturn(featureSetOperations);
78 | when(featureSetOperations.remove("FEATURES_1334", sut.getFeature())).thenReturn(1L);
79 |
80 | final boolean result = sut.disableFeature(1334L);
81 |
82 | verify(featureSetOperations, times(1)).remove("FEATURES_1334", sut.getFeature());
83 |
84 | assertThat(result).isTrue();
85 | }
86 |
87 | @Test
88 | public void enableFeatureTestDisabledFeature() {
89 | when(featureRedisTemplate.opsForSet()).thenReturn(featureSetOperations);
90 | when(featureSetOperations.add("FEATURES_1334", sut.getFeature())).thenReturn(1L);
91 |
92 | final boolean result = sut.enableFeature(1334L);
93 |
94 | verify(featureSetOperations, times(1)).add("FEATURES_1334", sut.getFeature());
95 |
96 | assertThat(result).isTrue();
97 | }
98 |
99 | @Test
100 | public void enableFeatureTestEnabledFeature() {
101 | when(featureRedisTemplate.opsForSet()).thenReturn(featureSetOperations);
102 | when(featureSetOperations.add("FEATURES_1334", sut.getFeature())).thenReturn(0L);
103 |
104 | final boolean result = sut.enableFeature(1334L);
105 |
106 | verify(featureSetOperations, times(1)).add("FEATURES_1334", sut.getFeature());
107 |
108 | assertThat(result).isFalse();
109 | }
110 |
111 | @Test
112 | public void isFeatureEnabledTest() {
113 | when(featureRedisTemplate.opsForSet()).thenReturn(featureSetOperations);
114 | when(featureSetOperations.isMember("FEATURES_1899", sut.getFeature())).thenReturn(true);
115 |
116 | final boolean featureEnabled = sut.isEnabled(1899L);
117 |
118 | assertThat(featureEnabled).isTrue();
119 | }
120 |
121 | @SuppressWarnings("unchecked")
122 | protected void _init() {
123 | principalService = mock(PrincipalService.class);
124 | followersService = mock(FollowersService.class);
125 | twitterService = mock(TwitterService.class);
126 | featureRedisTemplate = mock(RedisTemplate.class);
127 | featureSetOperations = mock(SetOperations.class);
128 | }
129 |
130 | protected Set followers(final Principal principal, final BiConsumer>, Set> l)
131 | throws WTFDYUMException {
132 | final Set followers = new HashSet<>(Arrays.asList(10L, 11L, 12L));
133 | l.accept(when(twitterService.getFollowers(principal.getUserId(), Optional.ofNullable(principal))), followers);
134 | return followers;
135 | }
136 |
137 | protected Principal principal(final long id) {
138 | when(principalService.getMembers()).thenReturn(new HashSet<>(Arrays.asList(id)));
139 | final Principal principal = new Principal(id, "Principal 1 Token", "Principal 1 Token Secret");
140 | when(principalService.get(id)).thenReturn(principal);
141 | return principal;
142 | }
143 |
144 | protected List unfollowers(final Principal principal, final Set followersIds,
145 | final BiConsumer>, Set> l) throws WTFDYUMException {
146 | final Set unfollowers = new HashSet<>(Arrays.asList(10L, 11L));
147 | l.accept(when(followersService.getUnfollowers(principal.getUserId(), followersIds)), unfollowers);
148 |
149 | // unfollowers 10 and 11 details :
150 | final User user10 = new User();
151 | user10.setId(10L);
152 | user10.setScreenName("user10");
153 |
154 | final User user11 = new User();
155 | user11.setId(11L);
156 | user11.setScreenName("user11");
157 |
158 | when(twitterService.getUsers(principal, 10L, 11L)).thenReturn(Arrays.asList(user10, user11));
159 | return Arrays.asList(user10, user11);
160 | }
161 |
162 | protected void verifyUnfollowDM(final Principal principal, final User unfollower) throws WTFDYUMException {
163 | verify(twitterService, times(1)).sendDirectMessage(principal, principal.getUserId(),
164 | String.format(DM_TEXT, unfollower.getScreenName()));
165 | }
166 |
167 | protected void verifyUnfollowTweet(final Principal principal, final User unfollower) throws WTFDYUMException {
168 | verify(twitterService, times(1)).tweet(principal, String.format(TWEET_TEXT, unfollower.getScreenName()));
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/src/test/java/com/jeanchampemont/wtfdyum/service/feature/NotifyUnfollowFeatureStrategyTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015, 2016 WTFDYUM
3 | *
4 | * This file is part of the WTFDYUM project.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package com.jeanchampemont.wtfdyum.service.feature;
19 |
20 | import com.jeanchampemont.wtfdyum.WTFDYUMApplication;
21 | import com.jeanchampemont.wtfdyum.dto.Event;
22 | import com.jeanchampemont.wtfdyum.dto.Principal;
23 | import com.jeanchampemont.wtfdyum.dto.User;
24 | import com.jeanchampemont.wtfdyum.dto.type.EventType;
25 | import com.jeanchampemont.wtfdyum.service.feature.impl.NotifyUnfollowFeatureStrategy;
26 | import org.junit.Before;
27 | import org.junit.Test;
28 | import org.junit.runner.RunWith;
29 | import org.springframework.boot.test.SpringApplicationConfiguration;
30 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
31 | import org.springframework.test.util.ReflectionTestUtils;
32 |
33 | import java.util.List;
34 | import java.util.Set;
35 |
36 | import static org.assertj.core.api.Assertions.assertThat;
37 | import static org.mockito.Mockito.times;
38 | import static org.mockito.Mockito.verify;
39 |
40 | @RunWith(SpringJUnit4ClassRunner.class)
41 | @SpringApplicationConfiguration(classes = WTFDYUMApplication.class)
42 | public class NotifyUnfollowFeatureStrategyTest extends AbstractFeatureStrategyTest {
43 |
44 | @Override
45 | @Before
46 | public void _init() {
47 | super._init();
48 | sut = new NotifyUnfollowFeatureStrategy(principalService, followersService, twitterService, DM_TEXT);
49 | ReflectionTestUtils.setField(sut, "featureRedisTemplate", featureRedisTemplate);
50 | }
51 |
52 | @Test
53 | public void completeCronTest() throws Exception {
54 | final Principal principal = principal(1L);
55 |
56 | final Set followers = followers(principal, (s, f) -> s.thenReturn(f));
57 |
58 | sut.completeCron(1L);
59 |
60 | // New followers list should be saved
61 | verify(followersService, times(1)).saveFollowers(1L, followers);
62 | }
63 |
64 | @Test
65 | public void cronTest() throws Exception {
66 | final Principal principal = principal(1L);
67 |
68 | final Set followers = followers(principal, (s, f) -> s.thenReturn(f));
69 |
70 | final List unfollowers = unfollowers(principal, followers, (s, u) -> s.thenReturn(u));
71 |
72 | final Set events = sut.cron(1L);
73 |
74 | verifyUnfollowDM(principal, unfollowers.get(0));
75 | verifyUnfollowDM(principal, unfollowers.get(1));
76 |
77 | assertThat(events.contains(new Event(EventType.UNFOLLOW, unfollowers.get(0).getScreenName())));
78 | assertThat(events.contains(new Event(EventType.UNFOLLOW, unfollowers.get(1).getScreenName())));
79 | }
80 |
81 | @Test
82 | public void hasCronTest() {
83 | assertThat(sut.hasCron()).isTrue();
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/test/java/com/jeanchampemont/wtfdyum/service/feature/TweetUnfollowFeatureStrategyTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015, 2016 WTFDYUM
3 | *
4 | * This file is part of the WTFDYUM project.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package com.jeanchampemont.wtfdyum.service.feature;
19 |
20 | import com.jeanchampemont.wtfdyum.WTFDYUMApplication;
21 | import com.jeanchampemont.wtfdyum.dto.Event;
22 | import com.jeanchampemont.wtfdyum.dto.Principal;
23 | import com.jeanchampemont.wtfdyum.dto.User;
24 | import com.jeanchampemont.wtfdyum.dto.type.EventType;
25 | import com.jeanchampemont.wtfdyum.service.feature.impl.TweetUnfollowFeatureStrategy;
26 | import org.junit.Before;
27 | import org.junit.Test;
28 | import org.junit.runner.RunWith;
29 | import org.springframework.boot.test.SpringApplicationConfiguration;
30 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
31 | import org.springframework.test.util.ReflectionTestUtils;
32 |
33 | import java.util.List;
34 | import java.util.Set;
35 |
36 | import static org.assertj.core.api.Assertions.assertThat;
37 | import static org.mockito.Mockito.times;
38 | import static org.mockito.Mockito.verify;
39 |
40 | @RunWith(SpringJUnit4ClassRunner.class)
41 | @SpringApplicationConfiguration(classes = WTFDYUMApplication.class)
42 | public class TweetUnfollowFeatureStrategyTest extends AbstractFeatureStrategyTest {
43 |
44 | @Override
45 | @Before
46 | public void _init() {
47 | super._init();
48 | sut = new TweetUnfollowFeatureStrategy(principalService, followersService, twitterService, TWEET_TEXT);
49 | ReflectionTestUtils.setField(sut, "featureRedisTemplate", featureRedisTemplate);
50 | }
51 |
52 | @Test
53 | public void completeCronTest() throws Exception {
54 | final Principal principal = principal(1L);
55 |
56 | final Set followers = followers(principal, (s, f) -> s.thenReturn(f));
57 |
58 | sut.completeCron(1L);
59 |
60 | // New followers list should be saved
61 | verify(followersService, times(1)).saveFollowers(1L, followers);
62 | }
63 |
64 | @Test
65 | public void cronTest() throws Exception {
66 | final Principal principal = principal(1L);
67 |
68 | final Set followers = followers(principal, (s, f) -> s.thenReturn(f));
69 |
70 | final List unfollowers = unfollowers(principal, followers, (s, u) -> s.thenReturn(u));
71 |
72 | final Set events = sut.cron(1L);
73 |
74 | verifyUnfollowTweet(principal, unfollowers.get(0));
75 | verifyUnfollowTweet(principal, unfollowers.get(1));
76 |
77 | assertThat(events.contains(new Event(EventType.UNFOLLOW, unfollowers.get(0).getScreenName())));
78 | assertThat(events.contains(new Event(EventType.UNFOLLOW, unfollowers.get(1).getScreenName())));
79 | }
80 |
81 | @Test
82 | public void hasCronTest() {
83 | assertThat(sut.hasCron()).isTrue();
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/test/java/com/jeanchampemont/wtfdyum/utils/ResponseListMockForTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015, 2016 WTFDYUM
3 | *
4 | * This file is part of the WTFDYUM project.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package com.jeanchampemont.wtfdyum.utils;
19 |
20 | import twitter4j.RateLimitStatus;
21 | import twitter4j.ResponseList;
22 |
23 | import java.util.ArrayList;
24 |
25 | public class ResponseListMockForTest extends ArrayListimplements ResponseList {
26 |
27 | private static final long serialVersionUID = -2964295762238022575L;
28 |
29 | @Override
30 | public int getAccessLevel() {
31 | throw new UnsupportedOperationException();
32 | }
33 |
34 | @Override
35 | public RateLimitStatus getRateLimitStatus() {
36 | throw new UnsupportedOperationException();
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/test/java/com/jeanchampemont/wtfdyum/web/AbstractControllerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015, 2016 WTFDYUM
3 | *
4 | * This file is part of the WTFDYUM project.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package com.jeanchampemont.wtfdyum.web;
19 |
20 | import com.jeanchampemont.wtfdyum.WTFDYUMApplication;
21 | import org.junit.Before;
22 | import org.junit.runner.RunWith;
23 | import org.springframework.boot.test.SpringApplicationConfiguration;
24 | import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
25 | import org.springframework.test.context.web.WebAppConfiguration;
26 | import org.springframework.test.web.servlet.MockMvc;
27 | import org.springframework.test.web.servlet.setup.MockMvcBuilders;
28 |
29 | /**
30 | * This class should be extended by all test class testing controllers.
31 | *
32 | * @author Jean
33 | */
34 | @RunWith(SpringJUnit4ClassRunner.class)
35 | @SpringApplicationConfiguration(classes = WTFDYUMApplication.class)
36 | @WebAppConfiguration
37 | public abstract class AbstractControllerTest {
38 |
39 | /** The mock mvc. */
40 | protected MockMvc mockMvc;
41 |
42 | /**
43 | * Setup : - Init mockMvc.
44 | */
45 | @Before
46 | public void setup() {
47 | mockMvc = MockMvcBuilders.standaloneSetup(getTestedController()).build();
48 | }
49 |
50 | protected abstract Object getTestedController();
51 | }
52 |
--------------------------------------------------------------------------------
/src/test/java/com/jeanchampemont/wtfdyum/web/AjaxControllerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016 WTFDYUM
3 | *
4 | * This file is part of the WTFDYUM project.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 | package com.jeanchampemont.wtfdyum.web;
20 |
21 | import com.jeanchampemont.wtfdyum.dto.Event;
22 | import com.jeanchampemont.wtfdyum.dto.type.EventType;
23 | import com.jeanchampemont.wtfdyum.service.AuthenticationService;
24 | import com.jeanchampemont.wtfdyum.service.UserService;
25 | import org.junit.Test;
26 | import org.junit.runner.RunWith;
27 | import org.mockito.InjectMocks;
28 | import org.mockito.Mock;
29 | import org.mockito.runners.MockitoJUnitRunner;
30 |
31 | import java.util.Arrays;
32 | import java.util.List;
33 |
34 | import static org.mockito.Mockito.when;
35 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
36 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
37 |
38 | @RunWith(value = MockitoJUnitRunner.class)
39 | public class AjaxControllerTest extends AbstractControllerTest {
40 |
41 | @Mock
42 | private AuthenticationService authenticationService;
43 |
44 | @Mock
45 | private UserService userService;
46 |
47 | @InjectMocks
48 | private AjaxController ajaxController;
49 |
50 | @Test
51 | public void recentEventsTest() throws Exception {
52 | List events = Arrays.asList(new Event(EventType.FEATURE_ENABLED, "test"), new Event(EventType.FEATURE_ENABLED, "test2"));
53 |
54 | when(authenticationService.getCurrentUserId()).thenReturn(128L);
55 | when(userService.getRecentEvents(128L, 10, 14)).thenReturn(events);
56 |
57 | mockMvc.perform(get("/ajax/recentEvents/14"))
58 | .andExpect(status().isOk())
59 | .andExpect(model().attribute("events", events))
60 | .andExpect(view().name("user/fragment/events"));
61 | }
62 |
63 | @Override
64 | protected Object getTestedController() {
65 | return ajaxController;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/test/java/com/jeanchampemont/wtfdyum/web/MainControllerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015, 2016 WTFDYUM
3 | *
4 | * This file is part of the WTFDYUM project.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package com.jeanchampemont.wtfdyum.web;
19 |
20 | import com.jeanchampemont.wtfdyum.dto.Event;
21 | import com.jeanchampemont.wtfdyum.dto.Principal;
22 | import com.jeanchampemont.wtfdyum.dto.type.EventType;
23 | import com.jeanchampemont.wtfdyum.service.AuthenticationService;
24 | import com.jeanchampemont.wtfdyum.service.PrincipalService;
25 | import com.jeanchampemont.wtfdyum.service.TwitterService;
26 | import com.jeanchampemont.wtfdyum.service.UserService;
27 | import org.junit.Test;
28 | import org.junit.runner.RunWith;
29 | import org.mockito.InjectMocks;
30 | import org.mockito.Mock;
31 | import org.mockito.runners.MockitoJUnitRunner;
32 | import org.springframework.mock.web.MockHttpSession;
33 | import org.springframework.test.util.ReflectionTestUtils;
34 | import twitter4j.auth.AccessToken;
35 | import twitter4j.auth.RequestToken;
36 |
37 | import javax.servlet.http.HttpSession;
38 |
39 | import static org.assertj.core.api.Assertions.assertThat;
40 | import static org.mockito.Matchers.anyString;
41 | import static org.mockito.Mockito.*;
42 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
43 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
44 |
45 | @RunWith(value = MockitoJUnitRunner.class)
46 | public class MainControllerTest extends AbstractControllerTest {
47 |
48 | @Mock
49 | private TwitterService twitterService;
50 |
51 | @Mock
52 | private PrincipalService principalService;
53 |
54 | @Mock
55 | private AuthenticationService authenticationService;
56 |
57 | @Mock
58 | private UserService userService;
59 |
60 | @InjectMocks
61 | private MainController mainController;
62 |
63 | @Test
64 | public void indexTest() throws Exception {
65 | mockMvc
66 | .perform(get("/"))
67 | .andExpect(status().isOk())
68 | .andExpect(view().name("index"));
69 | }
70 |
71 | @Test
72 | public void signinAlreadyAuthenticatedTest() throws Exception {
73 | when(authenticationService.isAuthenticated()).thenReturn(true);
74 |
75 | mockMvc
76 | .perform(get("/signin"))
77 | .andExpect(status().is3xxRedirection())
78 | .andExpect(redirectedUrl("/user"));
79 | }
80 |
81 | @Test
82 | public void signinCallbackTest() throws Exception {
83 | final RequestToken returnedRequestToken = new RequestToken("my_super_token", "");
84 |
85 | when(twitterService.signin(anyString())).thenReturn(returnedRequestToken);
86 | when(principalService.get(1203L)).thenReturn(null);
87 |
88 | final HttpSession session = mockMvc
89 | .perform(get("/signin"))
90 | .andExpect(status().is3xxRedirection())
91 | .andExpect(redirectedUrlPattern("http*://**/**my_super_token"))
92 | .andReturn()
93 | .getRequest()
94 | .getSession();
95 |
96 | assertThat(session).isNotNull();
97 | assertThat(session.getAttribute(MainController.SESSION_REQUEST_TOKEN)).isNotNull();
98 | assertThat(session.getAttribute(MainController.SESSION_REQUEST_TOKEN)).isEqualTo(returnedRequestToken);
99 |
100 | final AccessToken returnedAccessToken = new AccessToken("TOken", "secret");
101 | ReflectionTestUtils.setField(returnedAccessToken, "userId", 1203L);
102 |
103 | when(twitterService.completeSignin(returnedRequestToken, "42")).thenReturn(returnedAccessToken);
104 |
105 | mockMvc
106 | .perform(get("/signin/callback?oauth_verifier=42").session((MockHttpSession) session))
107 | .andExpect(status().is3xxRedirection())
108 | .andExpect(redirectedUrl("/user"));
109 |
110 | final Principal builtUser = new Principal(1203L, "TOken", "secret");
111 |
112 | verify(userService, times(1)).addEvent(1203L, new Event(EventType.REGISTRATION, null));
113 | verify(principalService, times(1)).saveUpdate(builtUser);
114 | verify(authenticationService, times(1)).authenticate(builtUser);
115 | }
116 |
117 | @Test
118 | public void signinTest() throws Exception {
119 | final RequestToken returnedRequestToken = new RequestToken("my_super_token", "");
120 |
121 | when(twitterService.signin(anyString())).thenReturn(returnedRequestToken);
122 |
123 | mockMvc
124 | .perform(get("/signin"))
125 | .andExpect(status().is3xxRedirection())
126 | .andExpect(redirectedUrlPattern("http*://**/**my_super_token"));
127 | }
128 |
129 | @Test
130 | public void signinTestMaxMembers() throws Exception {
131 | ReflectionTestUtils.setField(mainController, "maxMembers", 100);
132 |
133 | when(principalService.countMembers()).thenReturn(100);
134 |
135 | mockMvc
136 | .perform(get("/signin"))
137 | .andExpect(status().is5xxServerError());
138 | }
139 |
140 | @Override
141 | protected Object getTestedController() {
142 | return mainController;
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/src/test/java/com/jeanchampemont/wtfdyum/web/UserControllerTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015, 2016 WTFDYUM
3 | *
4 | * This file is part of the WTFDYUM project.
5 | *
6 | * Licensed under the Apache License, Version 2.0 (the "License");
7 | * you may not use this file except in compliance with the License.
8 | * 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, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 | package com.jeanchampemont.wtfdyum.web;
19 |
20 | import com.jeanchampemont.wtfdyum.dto.Event;
21 | import com.jeanchampemont.wtfdyum.dto.Feature;
22 | import com.jeanchampemont.wtfdyum.dto.Principal;
23 | import com.jeanchampemont.wtfdyum.dto.User;
24 | import com.jeanchampemont.wtfdyum.dto.type.EventType;
25 | import com.jeanchampemont.wtfdyum.service.*;
26 | import com.jeanchampemont.wtfdyum.utils.SessionManager;
27 | import com.jeanchampemont.wtfdyum.utils.WTFDYUMException;
28 | import com.jeanchampemont.wtfdyum.utils.WTFDYUMExceptionType;
29 | import org.junit.Test;
30 | import org.junit.runner.RunWith;
31 | import org.mockito.InjectMocks;
32 | import org.mockito.Mock;
33 | import org.mockito.runners.MockitoJUnitRunner;
34 |
35 | import java.util.Arrays;
36 | import java.util.List;
37 |
38 | import static org.hamcrest.Matchers.hasEntry;
39 | import static org.mockito.Mockito.*;
40 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
41 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
42 |
43 | @RunWith(value = MockitoJUnitRunner.class)
44 | public class UserControllerTest extends AbstractControllerTest {
45 |
46 | @Mock
47 | private TwitterService twitterService;
48 |
49 | @Mock
50 | private PrincipalService principalService;
51 |
52 | @Mock
53 | private AuthenticationService authenticationService;
54 |
55 | @Mock
56 | private UserService userService;
57 |
58 | @Mock
59 | private FeatureService featureService;
60 |
61 | @InjectMocks
62 | private UserController userController;
63 |
64 | @Test
65 | public void disableFeatureTest() throws Exception {
66 | when(authenticationService.getCurrentUserId()).thenReturn(12340L);
67 | when(featureService.disableFeature(12340L, Feature.NOTIFY_UNFOLLOW)).thenReturn(true);
68 |
69 | mockMvc
70 | .perform(get("/user/feature/disable/NOTIFY_UNFOLLOW"))
71 | .andExpect(status().is3xxRedirection())
72 | .andExpect(redirectedUrl("/user"));
73 |
74 | verify(featureService, times(1)).disableFeature(12340L, Feature.NOTIFY_UNFOLLOW);
75 | verify(userService, times(1)).addEvent(12340L,
76 | new Event(EventType.FEATURE_DISABLED, Feature.NOTIFY_UNFOLLOW.getShortName()));
77 | }
78 |
79 | @Test
80 | public void enableFeatureTest() throws Exception {
81 | when(authenticationService.getCurrentUserId()).thenReturn(12340L);
82 | when(featureService.enableFeature(12340L, Feature.NOTIFY_UNFOLLOW)).thenReturn(true);
83 |
84 | mockMvc
85 | .perform(get("/user/feature/enable/NOTIFY_UNFOLLOW"))
86 | .andExpect(status().is3xxRedirection())
87 | .andExpect(redirectedUrl("/user"));
88 |
89 | verify(featureService, times(1)).enableFeature(12340L, Feature.NOTIFY_UNFOLLOW);
90 | verify(userService, times(1)).addEvent(12340L,
91 | new Event(EventType.FEATURE_ENABLED, Feature.NOTIFY_UNFOLLOW.getShortName()));
92 | }
93 |
94 | @Test
95 | public void indexTest() throws Exception {
96 | final Principal principal = new Principal(1L, "tok", "toksec");
97 | SessionManager.setPrincipal(principal);
98 | final User u = new User();
99 |
100 | final List events = Arrays.asList(new Event(), new Event(EventType.REGISTRATION, ""));
101 |
102 | when(authenticationService.getCurrentUserId()).thenReturn(12340L);
103 | when(twitterService.getUser(principal, 12340L)).thenReturn(u);
104 | when(userService.getRecentEvents(12340L, 10)).thenReturn(events);
105 | when(featureService.isEnabled(12340L, Feature.NOTIFY_UNFOLLOW)).thenReturn(true);
106 |
107 | mockMvc
108 | .perform(get("/user"))
109 | .andExpect(status().isOk())
110 | .andExpect(view().name("user/index"))
111 | .andExpect(model().attribute("user", u))
112 | .andExpect(model().attribute("events", events))
113 | .andExpect(model().attribute("availableFeatures", Feature.values()))
114 | .andExpect(
115 | model().attribute("featuresStatus", hasEntry(Feature.NOTIFY_UNFOLLOW.name(), true)));
116 | }
117 |
118 | @Test
119 | public void indexTestTwitterErrorException() throws Exception {
120 | final Principal principal = new Principal(1L, "tok", "toksec");
121 | SessionManager.setPrincipal(principal);
122 |
123 | when(authenticationService.getCurrentUserId()).thenReturn(12340L);
124 | when(twitterService.getUser(principal, 12340L))
125 | .thenThrow(new WTFDYUMException(WTFDYUMExceptionType.TWITTER_ERROR));
126 |
127 | mockMvc
128 | .perform(get("/user"))
129 | .andExpect(status().is3xxRedirection())
130 | .andExpect(redirectedUrl("/"));
131 |
132 | verify(authenticationService, times(1)).logOut();
133 | }
134 |
135 | @Test
136 | public void logoutTest() throws Exception {
137 | mockMvc
138 | .perform(get("/user/logout"))
139 | .andExpect(status().is3xxRedirection())
140 | .andExpect(redirectedUrl("/"));
141 |
142 | verify(authenticationService, times(1)).logOut();
143 |
144 | }
145 |
146 | @Override
147 | protected Object getTestedController() {
148 | return userController;
149 | }
150 | }
151 |
--------------------------------------------------------------------------------