Skip to content

Commit ced1dfe

Browse files
committed
Resolves #643, test cases failed due to presence of global state in CallsCount. Because AppTest was executed before B2BServiceTest, it scheduled 1 sec timer using ThrottleTimerImpl class. While resetting it used that global CallCount class reset() method, which reset all counters. So that causes thread safety issue because of unintended sharing of application state between test cases, which is not a good practice.
1 parent db33cc5 commit ced1dfe

File tree

7 files changed

+32
-27
lines changed

7 files changed

+32
-27
lines changed

throttling/src/main/java/com/iluwatar/throttling/App.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,14 @@ public class App {
5353
* @param args main arguments
5454
*/
5555
public static void main(String[] args) {
56-
57-
Tenant adidas = new Tenant("Adidas", 5);
58-
Tenant nike = new Tenant("Nike", 6);
56+
CallsCount callsCount = new CallsCount();
57+
Tenant adidas = new Tenant("Adidas", 5, callsCount);
58+
Tenant nike = new Tenant("Nike", 6, callsCount);
5959

6060
ExecutorService executorService = Executors.newFixedThreadPool(2);
6161

62-
executorService.execute(() -> makeServiceCalls(adidas));
63-
executorService.execute(() -> makeServiceCalls(nike));
62+
executorService.execute(() -> makeServiceCalls(adidas, callsCount));
63+
executorService.execute(() -> makeServiceCalls(nike, callsCount));
6464

6565
executorService.shutdown();
6666
try {
@@ -73,9 +73,9 @@ public static void main(String[] args) {
7373
/**
7474
* Make calls to the B2BService dummy API
7575
*/
76-
private static void makeServiceCalls(Tenant tenant) {
77-
Throttler timer = new ThrottleTimerImpl(10);
78-
B2BService service = new B2BService(timer);
76+
private static void makeServiceCalls(Tenant tenant, CallsCount callsCount) {
77+
Throttler timer = new ThrottleTimerImpl(10, callsCount);
78+
B2BService service = new B2BService(timer, callsCount);
7979
for (int i = 0; i < 20; i++) {
8080
service.dummyCustomerApi(tenant);
8181
// Sleep is introduced to keep the output in check and easy to view and analyze the results.

throttling/src/main/java/com/iluwatar/throttling/B2BService.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,10 @@
3535
class B2BService {
3636

3737
private static final Logger LOGGER = LoggerFactory.getLogger(B2BService.class);
38+
private final CallsCount callsCount;
3839

39-
public B2BService(Throttler timer) {
40+
public B2BService(Throttler timer, CallsCount callsCount) {
41+
this.callsCount = callsCount;
4042
timer.start();
4143
}
4244

@@ -46,13 +48,13 @@ public B2BService(Throttler timer) {
4648
*/
4749
public int dummyCustomerApi(Tenant tenant) {
4850
String tenantName = tenant.getName();
49-
long count = CallsCount.getCount(tenantName);
51+
long count = callsCount.getCount(tenantName);
5052
LOGGER.debug("Counter for {} : {} ", tenant.getName(), count);
5153
if (count >= tenant.getAllowedCallsPerSecond()) {
5254
LOGGER.error("API access per second limit reached for: {}", tenantName);
5355
return -1;
5456
}
55-
CallsCount.incrementCount(tenantName);
57+
callsCount.incrementCount(tenantName);
5658
return getRandomCustomerId();
5759
}
5860

throttling/src/main/java/com/iluwatar/throttling/CallsCount.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,21 @@
3838
public final class CallsCount {
3939

4040
private static final Logger LOGGER = LoggerFactory.getLogger(CallsCount.class);
41-
private static Map<String, AtomicLong> tenantCallsCount = new ConcurrentHashMap<>();
41+
private Map<String, AtomicLong> tenantCallsCount = new ConcurrentHashMap<>();
4242

4343
/**
4444
* Add a new tenant to the map.
4545
* @param tenantName name of the tenant.
4646
*/
47-
public static void addTenant(String tenantName) {
47+
public void addTenant(String tenantName) {
4848
tenantCallsCount.putIfAbsent(tenantName, new AtomicLong(0));
4949
}
5050

5151
/**
5252
* Increment the count of the specified tenant.
5353
* @param tenantName name of the tenant.
5454
*/
55-
public static void incrementCount(String tenantName) {
55+
public void incrementCount(String tenantName) {
5656
tenantCallsCount.get(tenantName).incrementAndGet();
5757
}
5858

@@ -61,14 +61,14 @@ public static void incrementCount(String tenantName) {
6161
* @param tenantName name of the tenant.
6262
* @return the count of the tenant.
6363
*/
64-
public static long getCount(String tenantName) {
64+
public long getCount(String tenantName) {
6565
return tenantCallsCount.get(tenantName).get();
6666
}
6767

6868
/**
6969
* Resets the count of all the tenants in the map.
7070
*/
71-
public static void reset() {
71+
public void reset() {
7272
LOGGER.debug("Resetting the map.");
7373
for (Entry<String, AtomicLong> e : tenantCallsCount.entrySet()) {
7474
tenantCallsCount.put(e.getKey(), new AtomicLong(0));

throttling/src/main/java/com/iluwatar/throttling/Tenant.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@ public class Tenant {
3838
* @param allowedCallsPerSecond The number of calls allowed for a particular tenant.
3939
* @throws InvalidParameterException If number of calls is less than 0, throws exception.
4040
*/
41-
public Tenant(String name, int allowedCallsPerSecond) {
41+
public Tenant(String name, int allowedCallsPerSecond, CallsCount callsCount) {
4242
if (allowedCallsPerSecond < 0) {
4343
throw new InvalidParameterException("Number of calls less than 0 not allowed");
4444
}
4545
this.name = name;
4646
this.allowedCallsPerSecond = allowedCallsPerSecond;
47-
CallsCount.addTenant(name);
47+
callsCount.addTenant(name);
4848
}
4949

5050
public String getName() {

throttling/src/main/java/com/iluwatar/throttling/timer/ThrottleTimerImpl.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,12 @@
3737
*/
3838
public class ThrottleTimerImpl implements Throttler {
3939

40-
private int throttlePeriod;
41-
42-
public ThrottleTimerImpl(int throttlePeriod) {
40+
private final int throttlePeriod;
41+
private final CallsCount callsCount;
42+
43+
public ThrottleTimerImpl(int throttlePeriod, CallsCount callsCount) {
4344
this.throttlePeriod = throttlePeriod;
45+
this.callsCount = callsCount;
4446
}
4547

4648
/**
@@ -51,7 +53,7 @@ public void start() {
5153
new Timer(true).schedule(new TimerTask() {
5254
@Override
5355
public void run() {
54-
CallsCount.reset();
56+
callsCount.reset();
5557
}
5658
}, 0, throttlePeriod);
5759
}

throttling/src/test/java/com/iluwatar/throttling/B2BServiceTest.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,19 @@
3333
*/
3434
public class B2BServiceTest {
3535

36-
@Disabled
36+
private CallsCount callsCount = new CallsCount();
37+
3738
@Test
3839
public void dummyCustomerApiTest() {
39-
Tenant tenant = new Tenant("testTenant", 2);
40+
Tenant tenant = new Tenant("testTenant", 2, callsCount);
4041
// In order to assure that throttling limits will not be reset, we use an empty throttling implementation
4142
Throttler timer = () -> { };
42-
B2BService service = new B2BService(timer);
43+
B2BService service = new B2BService(timer, callsCount);
4344

4445
for (int i = 0; i < 5; i++) {
4546
service.dummyCustomerApi(tenant);
4647
}
47-
long counter = CallsCount.getCount(tenant.getName());
48+
long counter = callsCount.getCount(tenant.getName());
4849
assertEquals(2, counter, "Counter limit must be reached");
4950
}
5051
}

throttling/src/test/java/com/iluwatar/throttling/TenantTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public class TenantTest {
3636
@Test
3737
public void constructorTest() {
3838
assertThrows(InvalidParameterException.class, () -> {
39-
Tenant tenant = new Tenant("FailTenant", -1);
39+
Tenant tenant = new Tenant("FailTenant", -1, new CallsCount());
4040
});
4141
}
4242
}

0 commit comments

Comments
 (0)