1 | package dbnp.studycapturing |
---|
2 | |
---|
3 | import grails.test.* |
---|
4 | import org.apache.poi.ss.usermodel.Workbook |
---|
5 | import org.apache.poi.ss.usermodel.WorkbookFactory |
---|
6 | import org.apache.poi.ss.usermodel.Cell |
---|
7 | import grails.converters.JSON |
---|
8 | import org.dbnp.gdt.* |
---|
9 | import org.dbnp.gdt.AssayModule |
---|
10 | import org.dbnp.gdt.TemplateEntity |
---|
11 | import groovy.mock.interceptor.MockFor |
---|
12 | import org.dbnp.gdt.GdtService |
---|
13 | import org.dbnp.gdt.TemplateStringField |
---|
14 | |
---|
15 | /** |
---|
16 | * AssayServiceTests Test |
---|
17 | * |
---|
18 | * @author s.h.sikkema@gmail.com |
---|
19 | * @since 20101218 |
---|
20 | * @package dbnp.studycapturing |
---|
21 | * |
---|
22 | * Revision information: |
---|
23 | * $Rev$ |
---|
24 | * $Author$ |
---|
25 | * $Date$ |
---|
26 | */ |
---|
27 | class AssayServiceTests extends GrailsUnitTestCase { |
---|
28 | |
---|
29 | def service = new AssayService() |
---|
30 | |
---|
31 | protected void setUp() { |
---|
32 | super.setUp() |
---|
33 | |
---|
34 | |
---|
35 | mockDomain(Term, [ new Term(id: 1, name: 'Human')]) |
---|
36 | |
---|
37 | mockDomain(TemplateField, [ new TemplateField(id: 1, name: 'tf1', type: TemplateFieldType.STRING), |
---|
38 | new TemplateField(id: 2, name: 'tf2', type: TemplateFieldType.STRING), |
---|
39 | new TemplateField(id: 3, name: 'tf3', type: TemplateFieldType.STRING)]) |
---|
40 | |
---|
41 | mockDomain(Template, [ new Template(id: 1, fields: [TemplateField.get(1), TemplateField.get(2)]), |
---|
42 | new Template(id: 2, fields: [TemplateField.get(3)])]) |
---|
43 | |
---|
44 | def mockGdtService = [getTemplateFieldTypeByCasedName: { a -> TemplateStringField }] |
---|
45 | def mockLog = [ info:{a->println a},error:{a->println "Error: $a"}] |
---|
46 | |
---|
47 | mockDomain(Subject, [ new Subject(gdtService: mockGdtService, id: 1, name:'subject1', template: Template.get(1), species: Term.get(1)), |
---|
48 | new Subject(gdtService: mockGdtService, id: 2, name:'subject2', template: Template.get(2), species: Term.get(1))]) |
---|
49 | |
---|
50 | mockDomain(SamplingEvent, [ new SamplingEvent(id:1, startTime: 2, duration: 5, sampleTemplate: new Template()), |
---|
51 | new SamplingEvent(id:2, startTime: 12, duration: 15, sampleTemplate: new Template())]) |
---|
52 | |
---|
53 | mockDomain(Event, [ new Event(id: 1, startTime: 6, endTime: 7), new Event(id: 2, startTime: 8, endTime: 9)])//, new Event(id: 2, startTime: 8, endTime: 9)]) |
---|
54 | |
---|
55 | mockDomain(EventGroup, [ new EventGroup(id:1, name: 'EventGroup1', events: [Event.get(1)], samplingEvents: [SamplingEvent.get(1)]), |
---|
56 | new EventGroup(id:2, name: 'EventGroup2', events: [Event.get(2)], samplingEvents: [SamplingEvent.get(2)])]) |
---|
57 | |
---|
58 | mockDomain(Sample, [ new Sample(id: 1, name:'sample1', parentSubject: Subject.get(1), parentEvent: SamplingEvent.get(1), parentEventGroup: EventGroup.get(1)), |
---|
59 | new Sample(id: 2, name:'sample2', parentSubject: Subject.get(2), parentEvent: SamplingEvent.get(2), parentEventGroup: EventGroup.get(2))]) |
---|
60 | |
---|
61 | mockDomain(AssayModule, [ new AssayModule(id: 1, url: 'http://www.example.com') ]) |
---|
62 | |
---|
63 | mockDomain(Assay, [ new Assay(id: 1, module: AssayModule.get(1), samples: [Sample.get(1),Sample.get(2)]), |
---|
64 | new Assay(id: 2, module: AssayModule.get(1), samples: [])]) |
---|
65 | |
---|
66 | Subject.get(1).metaClass.static.log = mockLog |
---|
67 | |
---|
68 | Subject.get(1).setFieldValue('tf1', 'tfv1') |
---|
69 | Subject.get(1).setFieldValue('tf2', 'tfv2') |
---|
70 | Subject.get(2).setFieldValue('tf3', 'tfv3') |
---|
71 | |
---|
72 | // mock authenticationService |
---|
73 | service.authenticationService = [ |
---|
74 | isLoggedIn: { true }, |
---|
75 | logInRemotely: { a, b, c -> }, |
---|
76 | logOffRemotely: { a, b -> }, |
---|
77 | getLoggedInUser: { null } |
---|
78 | ] |
---|
79 | |
---|
80 | // mock moduleCommunicationService |
---|
81 | service.moduleCommunicationService = [ |
---|
82 | isModuleReachable: { a -> true }, |
---|
83 | callModuleRestMethodJSON: { consumer, path -> |
---|
84 | [['sample1', 'sample2', 'sample3'], |
---|
85 | ['measurement1','measurement2','measurement3','measurement4'], |
---|
86 | [1,2,3,4,5,6,7,8,9,10,11,12] ] |
---|
87 | } |
---|
88 | ] |
---|
89 | |
---|
90 | } |
---|
91 | |
---|
92 | protected void tearDown() { |
---|
93 | super.tearDown() |
---|
94 | } |
---|
95 | |
---|
96 | void testExportColumnWiseDataAsExcelFile() { |
---|
97 | |
---|
98 | def columnData = [ |
---|
99 | Category1: [Column1: [1,2,3], Column2: [4,5,6]], |
---|
100 | Category2: [Column3: [7,8,9], Column4: [10,11,12], Column5: [13,14,15]], |
---|
101 | EmptyCategory: [:] |
---|
102 | ] |
---|
103 | |
---|
104 | def rowData = [ |
---|
105 | ['Category1','','Category2','',''], |
---|
106 | ['Column1','Column2','Column3','Column4','Column5'], |
---|
107 | [1,4,7,10,13], |
---|
108 | [2,5,8,11,14], |
---|
109 | [3,6,9,12,15]] |
---|
110 | |
---|
111 | ByteArrayOutputStream baos = new ByteArrayOutputStream(1024) |
---|
112 | DataOutputStream dos = new DataOutputStream(baos) |
---|
113 | |
---|
114 | service.exportColumnWiseDataToExcelFile(columnData, dos, true) |
---|
115 | |
---|
116 | ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()) |
---|
117 | |
---|
118 | assertEquals 'Expected Excel contents', rowData, readExcelIntoArray(bais) |
---|
119 | |
---|
120 | } |
---|
121 | |
---|
122 | def readExcelIntoArray = { inputStream -> |
---|
123 | |
---|
124 | Workbook wb = WorkbookFactory.create(inputStream) |
---|
125 | |
---|
126 | def sheet = wb.getSheetAt(0) |
---|
127 | |
---|
128 | def readData = [] |
---|
129 | |
---|
130 | sheet.eachWithIndex { row, ri -> |
---|
131 | |
---|
132 | readData[ri] = [] |
---|
133 | |
---|
134 | row.eachWithIndex { cell, ci -> |
---|
135 | // TODO: what happens when there are empty cells |
---|
136 | readData[ri][ci] = (cell.cellType == Cell.CELL_TYPE_NUMERIC) ? cell.numericCellValue : cell.stringCellValue |
---|
137 | |
---|
138 | } |
---|
139 | |
---|
140 | } |
---|
141 | |
---|
142 | readData |
---|
143 | |
---|
144 | } |
---|
145 | |
---|
146 | // class to test writing non number/string values to excel |
---|
147 | class SomeCustomType { String toString() {'13'} } |
---|
148 | |
---|
149 | void testExportRowWiseDataToExcelFile() { |
---|
150 | |
---|
151 | SomeCustomType someCustomType = new SomeCustomType() |
---|
152 | |
---|
153 | def rowData = [ |
---|
154 | ['Category1','','Category2','',''], |
---|
155 | ['Column1','Column2','Column3','Column4','Column5'], |
---|
156 | [1,4,7,10,someCustomType], |
---|
157 | [2,5,8,11,null], |
---|
158 | [3,6,9,12,15]] |
---|
159 | |
---|
160 | ByteArrayOutputStream baos = new ByteArrayOutputStream(1024) |
---|
161 | DataOutputStream dos = new DataOutputStream(baos) |
---|
162 | |
---|
163 | service.exportRowWiseDataToExcelFile(rowData, dos, false) |
---|
164 | |
---|
165 | ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()) |
---|
166 | |
---|
167 | // replace custom type with expected written value |
---|
168 | rowData[2][4] = '13' |
---|
169 | rowData[3][4] = '' |
---|
170 | |
---|
171 | def result = readExcelIntoArray(bais) |
---|
172 | |
---|
173 | assertEquals 'Excel contents', rowData, result |
---|
174 | |
---|
175 | } |
---|
176 | |
---|
177 | void testExportRowWiseDataToExcelFileWithRealisticData() { |
---|
178 | |
---|
179 | def rowData = [ |
---|
180 | ['Subject Data', '', '', 'Sampling Event Data', '', '', 'Sample Data', '', ''], |
---|
181 | ['name', 'species', 'Gender', 'startTime', 'sampleTemplate', 'Sample volume', 'name', 'material', 'Text on vial'], |
---|
182 | [11, 'Homo Sapiens', 'Male', 367200, 'Human blood sample', 4.5, '11_A', 'blood plasma', 'T8.93650593495392']] |
---|
183 | |
---|
184 | ByteArrayOutputStream baos = new ByteArrayOutputStream(1024) |
---|
185 | DataOutputStream dos = new DataOutputStream(baos) |
---|
186 | |
---|
187 | service.exportRowWiseDataToExcelFile(rowData, dos, false) |
---|
188 | |
---|
189 | ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()) |
---|
190 | |
---|
191 | def result = readExcelIntoArray(bais) |
---|
192 | |
---|
193 | assertEquals 'Excel contents', rowData, result |
---|
194 | } |
---|
195 | |
---|
196 | void testTemplateFieldsAreCollected() { |
---|
197 | |
---|
198 | def assay = Assay.get(1) |
---|
199 | |
---|
200 | |
---|
201 | // collectAssayData(assay, fieldMap, measurementTokens) |
---|
202 | |
---|
203 | def fieldMap = [ |
---|
204 | 'Subject Data':[[name:'tf1'],[name:'tf2'],[name:'tf3'],[name:'species'],[name:'name']], |
---|
205 | 'Sampling Event Data':[[name:'startTime'],[name:'duration']], |
---|
206 | 'Sample Data':[[name:'name']], |
---|
207 | 'Event Group':[[name:'name']] |
---|
208 | ] |
---|
209 | |
---|
210 | def measurementTokens = [[name:'measurement1'], [name:'measurement2'], [name:'measurement3'], [name:'measurement4']] |
---|
211 | |
---|
212 | String.metaClass.'encodeAsURL' = {delegate} |
---|
213 | |
---|
214 | def assayData = service.collectAssayData(assay, fieldMap, measurementTokens) |
---|
215 | |
---|
216 | def sample1index = assayData.'Sample Data'.'name'.findIndexOf{it == 'sample1'} |
---|
217 | def sample2index = assayData.'Sample Data'.'name'.findIndexOf{it == 'sample2'} |
---|
218 | |
---|
219 | assertEquals 'Subject template field', ['tfv1',''], assayData.'Subject Data'.tf1[sample1index, sample2index] |
---|
220 | assertEquals 'Subject template field', ['tfv2',''], assayData.'Subject Data'.tf2[sample1index, sample2index] |
---|
221 | assertEquals 'Subject template field', ['','tfv3'], assayData.'Subject Data'.tf3[sample1index, sample2index] |
---|
222 | assertEquals 'Subject species template field', ['Human', 'Human'], assayData.'Subject Data'.species*.toString() |
---|
223 | assertEquals 'Subject name template field', ['subject1','subject2'], assayData.'Subject Data'.name[sample1index, sample2index] |
---|
224 | |
---|
225 | assertEquals 'Sampling event template fields', [2,12], assayData.'Sampling Event Data'.startTime[sample1index, sample2index] |
---|
226 | assertEquals 'Sampling event template fields', [5,15], assayData.'Sampling Event Data'.duration[sample1index, sample2index] |
---|
227 | // assertEquals 'Sampling event template fields', '[null, null]', assayData.'Sampling Event Data'.sampleTemplate.toString() |
---|
228 | assertEquals 'Sample template fields', ['sample1', 'sample2'], assayData.'Sample Data'.name[sample1index, sample2index] |
---|
229 | |
---|
230 | assertEquals 'Event group names', ['EventGroup1', 'EventGroup2'], assayData.'Event Group'.name[sample1index, sample2index] |
---|
231 | |
---|
232 | assertEquals 'Module Measurement Data', ['measurement1': [1,5,9], 'measurement2': [2,6,10], 'measurement3': [3,7,11], 'measurement4': [4,8,12]], assayData.'Module Measurement Data' |
---|
233 | } |
---|
234 | |
---|
235 | // // Test for out of memory exception when exporting large excel workbooks |
---|
236 | // // - xls format can handle max 256 columns |
---|
237 | // // - but, xls format can handle more data (1000000 cells, no problem -> 27.2 MB) |
---|
238 | // // - we'll need a good method to overcome the xlsx heap space problem |
---|
239 | // void testExportLargeExcelWorkbook() { |
---|
240 | // |
---|
241 | // def file = new File( '/tmp', 'tmpFile.xls' ) |
---|
242 | // |
---|
243 | // def os = file.newOutputStream() |
---|
244 | // |
---|
245 | // def rowData = (0..1).collect { row -> |
---|
246 | // |
---|
247 | // (0..256).collect { col -> |
---|
248 | // "$row - $col" |
---|
249 | // } |
---|
250 | // |
---|
251 | // } |
---|
252 | // |
---|
253 | //// try { |
---|
254 | // service.exportRowWiseDataToExcelFile rowData, os, false |
---|
255 | //// } catch (Exception e) { |
---|
256 | //// e.printStackTrace() |
---|
257 | //// assert false |
---|
258 | //// } finally { |
---|
259 | // os.flush() |
---|
260 | //// file.delete() |
---|
261 | //// } |
---|
262 | // } |
---|
263 | |
---|
264 | |
---|
265 | } |
---|