1 | package clarin.cmdi.componentregistry.rest; |
---|
2 | |
---|
3 | import clarin.cmdi.componentregistry.RegistrySpace; |
---|
4 | import clarin.cmdi.componentregistry.impl.database.ComponentRegistryTestDatabase; |
---|
5 | import clarin.cmdi.componentregistry.model.BaseDescription; |
---|
6 | import clarin.cmdi.componentregistry.model.ComponentDescription; |
---|
7 | import clarin.cmdi.componentregistry.model.ProfileDescription; |
---|
8 | import clarin.cmdi.componentregistry.model.RegisterResponse; |
---|
9 | |
---|
10 | import com.sun.jersey.api.client.ClientResponse; |
---|
11 | import com.sun.jersey.multipart.FormDataMultiPart; |
---|
12 | |
---|
13 | import java.io.InputStream; |
---|
14 | import java.util.ArrayList; |
---|
15 | import java.util.Arrays; |
---|
16 | import java.util.Collections; |
---|
17 | import java.util.Comparator; |
---|
18 | import java.util.List; |
---|
19 | |
---|
20 | import javax.ws.rs.core.MediaType; |
---|
21 | |
---|
22 | import org.junit.Before; |
---|
23 | import org.junit.Test; |
---|
24 | import org.slf4j.Logger; |
---|
25 | import org.slf4j.LoggerFactory; |
---|
26 | import org.springframework.beans.factory.annotation.Autowired; |
---|
27 | import org.springframework.jdbc.core.JdbcTemplate; |
---|
28 | |
---|
29 | import static clarin.cmdi.componentregistry.rest.ComponentRegistryRestService.REGISTRY_SPACE_PARAM; |
---|
30 | import static org.junit.Assert.*; |
---|
31 | |
---|
32 | /** |
---|
33 | * |
---|
34 | * @author george.georgovassilis@mpi.nl |
---|
35 | * |
---|
36 | */ |
---|
37 | public class ConcurrentRestServiceTest extends |
---|
38 | ComponentRegistryRestServiceTestCase { |
---|
39 | |
---|
40 | private final static Logger LOG = LoggerFactory |
---|
41 | .getLogger(ConcurrentRestServiceTest.class); |
---|
42 | private final int NR_OF_PROFILES = 20; |
---|
43 | private final int NR_OF_COMPONENTS = 20; |
---|
44 | |
---|
45 | @Autowired |
---|
46 | private JdbcTemplate jdbcTemplate; |
---|
47 | |
---|
48 | |
---|
49 | @Before |
---|
50 | public void init() { |
---|
51 | ComponentRegistryTestDatabase.resetAndCreateAllTables(jdbcTemplate); |
---|
52 | createUserRecord(); |
---|
53 | } |
---|
54 | |
---|
55 | @Test |
---|
56 | public void testConcurrentRegisterProfile() throws Exception { |
---|
57 | List<String> errors = new ArrayList<String>(); |
---|
58 | List<Thread> ts = new ArrayList<Thread>(); |
---|
59 | |
---|
60 | registerProfiles(ts, NR_OF_PROFILES, errors, RegistrySpace.PRIVATE); |
---|
61 | //a profile can be first registered (created) only in private space, and then moved. |
---|
62 | //registerProfiles(ts, NR_OF_PROFILES, errors, RegistrySpace.PUBLISHED); |
---|
63 | |
---|
64 | registerComponents(ts, NR_OF_COMPONENTS, errors, RegistrySpace.PRIVATE); |
---|
65 | //a profile can be first registered (created) only in private space, and then moved. |
---|
66 | //registerComponents(ts, NR_OF_COMPONENTS, errors, RegistrySpace.PUBLISHED); |
---|
67 | runAllThreads(ts); |
---|
68 | if (errors.size() > 0) { |
---|
69 | System.out.println(Arrays.toString(errors.toArray())); |
---|
70 | for (String e : errors) |
---|
71 | System.err.println(e); |
---|
72 | fail(); |
---|
73 | } |
---|
74 | assertProfiles(NR_OF_PROFILES, RegistrySpace.PRIVATE); |
---|
75 | //assertProfiles(NR_OF_PROFILES, RegistrySpace.PUBLISHED); |
---|
76 | |
---|
77 | assertComponents(NR_OF_COMPONENTS, RegistrySpace.PRIVATE); |
---|
78 | //assertComponents(NR_OF_COMPONENTS, RegistrySpace.PUBLISHED); |
---|
79 | } |
---|
80 | |
---|
81 | private void assertProfiles(int nrOfProfiles, RegistrySpace registrySpace) { |
---|
82 | List<ProfileDescription> response = getAuthenticatedResource( |
---|
83 | getResource().path("/registry/profiles").queryParam( |
---|
84 | REGISTRY_SPACE_PARAM, registrySpace.name())).accept( |
---|
85 | MediaType.APPLICATION_XML).get(PROFILE_LIST_GENERICTYPE); |
---|
86 | Collections.sort(response, descriptionComparator); |
---|
87 | assertEquals("half should be deleted", nrOfProfiles / 2, |
---|
88 | response.size()); |
---|
89 | for (int i = 0; i < nrOfProfiles / 2; i++) { |
---|
90 | ProfileDescription desc = response.get(i); |
---|
91 | assertEquals("Test Profile" + (i * 2 + 1000), desc.getName()); |
---|
92 | assertEquals("Test Profile" + (i * 2 + 1000) + " Description", |
---|
93 | desc.getDescription()); |
---|
94 | } |
---|
95 | } |
---|
96 | |
---|
97 | private Comparator<BaseDescription> descriptionComparator = new Comparator<BaseDescription>() { |
---|
98 | |
---|
99 | @Override |
---|
100 | public int compare(BaseDescription o1, BaseDescription o2) { |
---|
101 | return o1.getName().compareTo(o2.getName()); |
---|
102 | } |
---|
103 | }; |
---|
104 | |
---|
105 | private void assertComponents(int nrOfComponents, RegistrySpace registrySpace) { |
---|
106 | List<ComponentDescription> cResponse = getAuthenticatedResource( |
---|
107 | getResource().path("/registry/components").queryParam( |
---|
108 | REGISTRY_SPACE_PARAM, registrySpace.name())).accept( |
---|
109 | MediaType.APPLICATION_XML).get(COMPONENT_LIST_GENERICTYPE); |
---|
110 | Collections.sort(cResponse, descriptionComparator); |
---|
111 | assertEquals("half should be deleted", nrOfComponents / 2, |
---|
112 | cResponse.size()); |
---|
113 | for (int i = 0; i < nrOfComponents / 2; i++) { |
---|
114 | ComponentDescription desc = cResponse.get(i); |
---|
115 | assertEquals("Test Component" + (i * 2 + 1000), desc.getName()); |
---|
116 | assertEquals("Test Component" + (i * 2 + 1000) + " Description", |
---|
117 | desc.getDescription()); |
---|
118 | } |
---|
119 | } |
---|
120 | |
---|
121 | private void runAllThreads(List<Thread> ts) throws InterruptedException { |
---|
122 | for (Thread thread : ts) { |
---|
123 | thread.start(); |
---|
124 | thread.join(10); |
---|
125 | } |
---|
126 | for (Thread thread : ts) { |
---|
127 | thread.join(); // Wait till all are finished |
---|
128 | } |
---|
129 | } |
---|
130 | |
---|
131 | private void registerProfiles(List<Thread> ts, int size, |
---|
132 | final List<String> errors, RegistrySpace registrySpace) |
---|
133 | throws InterruptedException { |
---|
134 | for (int i = 0; i < size; i++) { |
---|
135 | final boolean shouldDelete = (i % 2) == 1; |
---|
136 | LOG.debug("Profile {} should be registered in {} and {}", |
---|
137 | new Object[] { i + 1000, |
---|
138 | registrySpace.name(), |
---|
139 | shouldDelete ? "ALSO DELETED" : "not deleted" }); |
---|
140 | Thread thread = createThread("/registry/profiles/", registrySpace, |
---|
141 | "Test Profile" + (i + 1000), shouldDelete, |
---|
142 | RegistryTestHelper.getTestProfileContent(), errors); |
---|
143 | ts.add(thread); |
---|
144 | } |
---|
145 | } |
---|
146 | |
---|
147 | private void registerComponents(List<Thread> ts, int size, |
---|
148 | final List<String> errors, RegistrySpace registrySpace) |
---|
149 | throws InterruptedException { |
---|
150 | for (int i = 0; i < size; i++) { |
---|
151 | final boolean shouldDelete = (i % 2) == 1; |
---|
152 | LOG.debug("Component {} should be registered in {} and {}", |
---|
153 | new Object[] { i + 1000, |
---|
154 | registrySpace.name(), |
---|
155 | shouldDelete ? "ALSO DELETED" : "not deleted" }); |
---|
156 | Thread thread = createThread("/registry/components/", registrySpace, |
---|
157 | "Test Component" + (i + 1000), shouldDelete, |
---|
158 | RegistryTestHelper.getComponentTestContent(), errors); |
---|
159 | ts.add(thread); |
---|
160 | } |
---|
161 | } |
---|
162 | |
---|
163 | private Thread createThread(final String path, final RegistrySpace registrySpace, |
---|
164 | final String name, final boolean alsoDelete, InputStream content, |
---|
165 | final List<String> errors) throws InterruptedException { |
---|
166 | final FormDataMultiPart form = new FormDataMultiPart(); |
---|
167 | form.field(IComponentRegistryRestService.DATA_FORM_FIELD, content, |
---|
168 | MediaType.APPLICATION_OCTET_STREAM_TYPE); |
---|
169 | form.field(IComponentRegistryRestService.NAME_FORM_FIELD, name); |
---|
170 | form.field(IComponentRegistryRestService.DESCRIPTION_FORM_FIELD, name |
---|
171 | + " Description"); |
---|
172 | Thread t = new Thread(new Runnable() { |
---|
173 | |
---|
174 | @Override |
---|
175 | public void run() { |
---|
176 | long timestamp=-System.currentTimeMillis(); |
---|
177 | try { |
---|
178 | // System.out.println("THREAD STARTED"+Thread.currentThread().getName()); |
---|
179 | RegisterResponse registerResponse = getAuthenticatedResource( |
---|
180 | getResource().path(path)).type( |
---|
181 | MediaType.MULTIPART_FORM_DATA).post( |
---|
182 | RegisterResponse.class, form); |
---|
183 | if (!registerResponse.isRegistered()) { |
---|
184 | errors.add("Failed to register " |
---|
185 | + Arrays.toString(registerResponse.getErrors() |
---|
186 | .toArray())); |
---|
187 | } |
---|
188 | LOG.debug(">>>>>>>>>>>>>>>> [Thread " + hashCode() |
---|
189 | + "] REGISTERING DESCRIPTION " + name + " " |
---|
190 | + registerResponse.getDescription().getId() |
---|
191 | + registrySpace.name() |
---|
192 | + (alsoDelete ? " alsoDelete" : "")); |
---|
193 | if (alsoDelete) { |
---|
194 | LOG.debug(">>>>>>>>>>>>>>>> [Thread " |
---|
195 | + hashCode() |
---|
196 | + "] DELETING DESCRIPTION " |
---|
197 | + name |
---|
198 | + " " |
---|
199 | + registerResponse.getDescription().getId() |
---|
200 | + registrySpace.name() |
---|
201 | + (alsoDelete ? " alsoDelete" : "")); |
---|
202 | ClientResponse response = getAuthenticatedResource( |
---|
203 | getResource().path( |
---|
204 | path |
---|
205 | + registerResponse |
---|
206 | .getDescription() |
---|
207 | .getId())) |
---|
208 | .delete(ClientResponse.class); |
---|
209 | if (response.getStatus() != 200) { |
---|
210 | errors.add("Failed to delete " |
---|
211 | + registerResponse.getDescription()); |
---|
212 | } |
---|
213 | } |
---|
214 | // System.out.println("THREAD FINISHED"+Thread.currentThread().getName()); |
---|
215 | } finally { |
---|
216 | timestamp+=System.currentTimeMillis(); |
---|
217 | LOG.info(Thread.currentThread().getName()+" duration: "+timestamp+" ms"); |
---|
218 | } |
---|
219 | } |
---|
220 | }); |
---|
221 | return t; |
---|
222 | |
---|
223 | } |
---|
224 | } |
---|