View Javadoc

1   /**
2    * Copyright 2012 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10   * software distributed under the License is distributed on an "AS IS"
11   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing
13   * permissions and limitations under the License.
14   *
15   * Created by Daniel on 6/7/12
16   */
17  package org.kuali.student.enrollment.class2.courseoffering.service.impl;
18  
19  import org.apache.commons.lang.StringUtils;
20  import org.junit.Test;
21  import org.junit.runner.RunWith;
22  import org.kuali.student.enrollment.class2.courseoffering.service.CourseOfferingCodeGenerator;
23  import org.kuali.student.enrollment.courseoffering.dto.ActivityOfferingInfo;
24  import org.kuali.student.enrollment.courseoffering.dto.CourseOfferingInfo;
25  import org.springframework.test.context.ContextConfiguration;
26  import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
27  
28  import javax.annotation.Resource;
29  import java.util.ArrayList;
30  import java.util.Collections;
31  import java.util.HashMap;
32  import java.util.List;
33  import java.util.Map;
34  import java.util.concurrent.Callable;
35  import java.util.concurrent.ExecutionException;
36  import java.util.concurrent.ExecutorService;
37  import java.util.concurrent.Executors;
38  import java.util.concurrent.Future;
39  
40  import static org.junit.Assert.assertEquals;
41  import static org.junit.Assert.assertTrue;
42  
43  /**
44   * This class provides unit tests for CourseOfferingCodeGeneratorImpl
45   *
46   * @author Kuali Student Team
47   */
48  @RunWith(SpringJUnit4ClassRunner.class)
49  @ContextConfiguration(locations = {"classpath:co-test-context.xml"})
50  public class TestCourseOfferingCodeGeneratorImpl {
51  
52      @Resource
53      CourseOfferingCodeGenerator offeringCodeGenerator;
54  
55  
56      private Map<String, Object> _makeDefaultMap(String coCode, List<String> aoCodes){
57          Map<String, Object> mRet = new HashMap<String,Object>();
58  
59          mRet.put(CourseOfferingCodeGenerator.COURSE_OFFERING_CODE_KEY, coCode);
60          mRet.put(CourseOfferingCodeGenerator.ACTIVITY_OFFERING_CODE_LIST_KEY, aoCodes);
61          return mRet;
62      }
63  
64      @Test
65      public void testGenerator(){
66  
67          String code;
68          String courseOfferingCode = "ENGL101";
69          code = offeringCodeGenerator.generateActivityOfferingCode(_makeDefaultMap(courseOfferingCode, new ArrayList<String>()));
70          assertEquals("A",code);
71  
72          List<String> aos = new ArrayList<String>();
73          for(char c='A';c<='Z';c++){
74  
75              aos.add(String.valueOf(c));
76          }
77  
78          Map<String, Object> propMap = _makeDefaultMap(courseOfferingCode, aos);
79          code = offeringCodeGenerator.generateActivityOfferingCode(propMap);
80          assertEquals("AA",code);
81  
82          aos.remove(3);
83  
84          code = offeringCodeGenerator.generateActivityOfferingCode(propMap);
85          assertEquals("D",code);
86  
87      }
88  
89      @Test
90      public void testGetNextCode(){
91  
92          CourseOfferingCodeGeneratorDBImpl dbImpl = (CourseOfferingCodeGeneratorDBImpl)offeringCodeGenerator;
93  
94          assertEquals("A",dbImpl.getNextCode(""));
95          assertEquals("E",dbImpl.getNextCode("D"));
96          assertEquals("AA",dbImpl.getNextCode("Z"));
97          assertEquals("AF",dbImpl.getNextCode("AE"));
98          assertEquals("BA",dbImpl.getNextCode("AZ"));
99          assertEquals("BF",dbImpl.getNextCode("BE"));
100         assertEquals("ZB",dbImpl.getNextCode("ZA"));
101         assertEquals("AAA", dbImpl.getNextCode("ZZ"));
102         assertEquals("AAF",dbImpl.getNextCode("AAE"));
103         assertEquals("ABA",dbImpl.getNextCode("AAZ"));
104         assertEquals("ABG",dbImpl.getNextCode("ABF"));
105         assertEquals("AAAA",dbImpl.getNextCode("ZZZ"));
106         assertEquals("AAEB",dbImpl.getNextCode("AAEA"));
107         assertEquals("AAZB",dbImpl.getNextCode("AAZA"));
108         assertEquals("ABAA",dbImpl.getNextCode("AAZZ"));
109         assertEquals("AZAC",dbImpl.getNextCode("AZAB"));
110         assertEquals("ZZZD",dbImpl.getNextCode("ZZZC"));
111         assertEquals("AAAAA",dbImpl.getNextCode("ZZZZ"));
112     }
113 
114     @Test
115     public void testGenerateCourseOfferingInternalCode(){
116 
117         String code;
118         code = offeringCodeGenerator.generateCourseOfferingInternalCode(new ArrayList<CourseOfferingInfo>());
119         assertEquals("A",code);
120 
121         List<CourseOfferingInfo> cos = new ArrayList<CourseOfferingInfo>();
122         for(char c='A';c<='Z';c++){
123             CourseOfferingInfo a = new CourseOfferingInfo();
124             a.setCourseNumberSuffix(String.valueOf(c));
125 
126             cos.add(a);
127         }
128         code = offeringCodeGenerator.generateCourseOfferingInternalCode(cos);
129         assertEquals("AA",code);
130 
131         cos.remove(3);
132 
133         code = offeringCodeGenerator.generateCourseOfferingInternalCode(cos);
134         assertEquals("D",code);
135     }
136 
137     protected List<String> _getBaseAOListNew(){
138            List<String> l = new ArrayList<String>();
139         l.add("A");
140         l.add("B");
141         l.add("C");
142         return l;
143     }
144 
145     protected List<ActivityOfferingInfo> _getBaseAOList(){
146         List<ActivityOfferingInfo> aoList = new ArrayList<ActivityOfferingInfo>();
147 
148         String courseOfferingCode = "ENGL102";
149 
150         ActivityOfferingInfo ao1 = new ActivityOfferingInfo();
151         ao1.setActivityCode("A");
152         ao1.setCourseOfferingCode(courseOfferingCode);
153         aoList.add(ao1);
154 
155         ActivityOfferingInfo ao2 = new ActivityOfferingInfo();
156         ao2.setActivityCode("B");
157         ao2.setCourseOfferingCode(courseOfferingCode);
158         aoList.add(ao2);
159 
160         ActivityOfferingInfo ao3 = new ActivityOfferingInfo();
161         ao3.setActivityCode("C");
162         ao3.setCourseOfferingCode(courseOfferingCode);
163         aoList.add(ao3);
164 
165 
166         return aoList;
167     }
168 
169 
170     @Test
171     public void testGenerateActivityOfferingCode(){
172 
173         String courseOfferingCode = "ENGL103";
174 
175         List<String> aoList = _getBaseAOListNew();
176         Map<String, Object> propMap = _makeDefaultMap(courseOfferingCode, aoList);
177 
178         String nextCode = offeringCodeGenerator.generateActivityOfferingCode(propMap);
179 
180         // the list passed in above is A,B,C so the next should be D
181         assertTrue("D".equals(nextCode));
182 
183         // Lets add a gap
184 
185         aoList.add("E");
186 
187         nextCode = offeringCodeGenerator.generateActivityOfferingCode(propMap);
188 
189         // the list passed in above is A,B,C,D,F so we should fill in the gap with E
190         assertTrue ("D".equals(nextCode));
191 
192     }
193 
194 
195     /**
196      *     This class is set to ignore right now, but should be set to @Test once our concurrency
197      *     issue is solved.
198      */
199     @Test
200     public void testGenerateActivityOfferingCodeMultiThread(){
201         try{
202             test("ENGL104", 6);
203         }catch (Exception ex){
204             ex.printStackTrace();
205         }
206     }
207 
208     private void test(final String courseOfferingCode, final int threadCount) throws InterruptedException, ExecutionException {
209 
210 
211         Callable<String> task = new Callable<String>() {
212 
213             @Override
214 
215             public String call() {
216 
217                 return offeringCodeGenerator.generateActivityOfferingCode(_makeDefaultMap(courseOfferingCode, new ArrayList <String>()));
218 
219             }
220 
221         };
222 
223         List<Callable<String>> tasks = Collections.nCopies(threadCount, task);
224 
225         ExecutorService executorService = Executors.newFixedThreadPool(threadCount);
226 
227         List<Future<String>> futures = executorService.invokeAll(tasks);
228 
229         List<String> resultList = new ArrayList<String>(futures.size());
230 
231         // Check for exceptions
232 
233         for (Future<String> future : futures) {
234 
235             // Throws an exception if an exception was thrown by the task.
236 
237             resultList.add(future.get());
238 
239         }
240 
241         // Validate the IDs
242 
243         assert (futures.size() ==  threadCount);
244 
245         List<String> expectedList = new ArrayList<String>(threadCount);
246 
247         String nextCode = "";
248         for (long i = 1; i <= threadCount; i++) {
249             nextCode = getNextCode(nextCode);
250             expectedList.add(nextCode);
251 
252         }
253 
254         Collections.sort(resultList);
255 
256         System.out.println("Expected/Got: \n" + expectedList + "\n" + resultList);
257 
258         for(int i=0;i< resultList.size(); i++){
259             assertTrue("\nWas expecting \n[" + expectedList.get(i) + "] but got \n[" + resultList.get(i) + "]\n" , expectedList.get(i).equals(resultList.get(i)));
260         }
261 
262     }
263 
264     public String getNextCode(String source){
265         if (StringUtils.isEmpty(source)){
266             return "A";
267         } else if (StringUtils.endsWithIgnoreCase(source,"Z")){
268             return getNextCode(StringUtils.substringBeforeLast(source,"Z")) + "A";
269         } else {
270             char lastLetter = source.charAt(source.length()-1);
271             return StringUtils.substringBeforeLast(source,""+lastLetter) + ++lastLetter;
272         }
273     }
274 
275 }