1 /*
2 * Copyright (C) 2013, Northwestern University and Argonne National Laboratory
3 * See COPYRIGHT notice in top-level directory.
4 */
5 /* $Id: header_consistency.c 2744 2016-12-28 16:25:22Z wkliao $ */
6
7 /* This program tests if PnetCDF can detect file header inconsistency and
8 * overwrite the inconsistent header with root's.
9 * This program is designed to run on more than 2 MPI processes.
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <libgen.h> /* basename() */
16 #include <mpi.h>
17 #include <pnetcdf.h>
18 #include <testutils.h>
19
20 #define ERR_EXP(e, exp) {if (e != exp) { printf("Error (line %d): expecting error code %s but got %s\n", __LINE__, nc_err_code_name(exp), nc_err_code_name(e)); nerrs++; }}
21 #define ERR_EXP2(e, exp1, exp2) {if (e != exp1 && e != exp2 && e != NC_EFILE) { printf("Error (line %d): expecting error code %s or %s but got %s\n", __LINE__, nc_err_code_name(exp1), nc_err_code_name(exp2), nc_err_code_name(e)); nerrs++; }}
22
23 #define CHECK_ERR(expect) { \
24 if (safe_mode) { \
25 if (err != NC_EMULTIDEFINE && err != expect) { \
26 printf("Error (line %d): expecting error code NC_EMULTIDEFINE or %s but got %s\n", __LINE__, nc_err_code_name(expect), nc_err_code_name(err)); \
27 nerrs++; \
28 } \
29 } \
30 else if (rank > 0) { \
31 if (err != expect) { \
32 printf("Error (line %d): expecting error code %s but got %s\n", __LINE__, nc_err_code_name(expect), nc_err_code_name(err)); \
33 nerrs++; \
34 } \
35 } \
36 }
37
38 #define ERR {if(err!=NC_NOERR) {printf("Error(%d) at line %d: %s\n",err,__LINE__,ncmpi_strerror(err)); nerrs++; }}
39
40 /*----< test_open_mode() >----------------------------------------------------*/
41 static
test_open_mode(char * filename,int safe_mode)42 int test_open_mode(char *filename, int safe_mode)
43 {
44 int err, rank, ncid, cmode, omode, nerrs=0;
45 MPI_Info info=MPI_INFO_NULL;
46 MPI_Comm comm=MPI_COMM_WORLD;
47
48 MPI_Comm_rank(comm, &rank);
49
50 /* Test inconsistent cmode -----------------------------------------------*/
51 cmode = NC_CLOBBER|NC_64BIT_OFFSET;
52 if (rank == 0) cmode = NC_CLOBBER;
53 err = ncmpi_create(comm, filename, cmode, info, &ncid);
54 if (safe_mode)
55 ERR_EXP(err, NC_EMULTIDEFINE_CMODE)
56 else {
57 if (rank > 0) ERR_EXP(err, NC_EMULTIDEFINE_CMODE)
58 err = ncmpi_close(ncid); ERR
59 }
60
61 /* Test inconsistent omode -----------------------------------------------*/
62 omode = NC_WRITE;
63 if (rank == 0) omode = NC_NOWRITE;
64 err = ncmpi_open(comm, filename, omode, info, &ncid);
65 if (safe_mode)
66 ERR_EXP(err, NC_EMULTIDEFINE_OMODE)
67 else {
68 if (rank > 0) ERR_EXP(err, NC_EMULTIDEFINE_OMODE)
69 err = ncmpi_close(ncid); ERR
70 }
71
72 return nerrs;
73 }
74
75 /*----< test_dim() >----------------------------------------------------------*/
76 static
test_dim(char * filename,int safe_mode)77 int test_dim(char *filename, int safe_mode)
78 {
79 int err, rank, ncid, cmode, dimid1, dimid2, dimid3, nerrs=0;
80 MPI_Info info=MPI_INFO_NULL;
81 MPI_Comm comm=MPI_COMM_WORLD;
82
83 MPI_Comm_rank(comm, &rank);
84 cmode = NC_CLOBBER|NC_64BIT_OFFSET;
85
86 /* Test inconsistency on dimension names ---------------------------------*/
87 err = ncmpi_create(comm, filename, cmode, info, &ncid); ERR
88 if (rank == 0)
89 err = ncmpi_def_dim(ncid, "y", 100, &dimid1);
90 else
91 err = ncmpi_def_dim(ncid, "xx", 100, &dimid1);
92 if (safe_mode)
93 CHECK_ERR(NC_EMULTIDEFINE_DIM_NAME)
94 else
95 ERR
96 err = ncmpi_enddef(ncid); ERR
97
98 if (safe_mode) {
99 /* no processes should be able to see dim "y" */
100 err = ncmpi_inq_dimid(ncid, "y", &dimid2);
101 CHECK_ERR(NC_EBADDIM)
102
103 /* no process should be able to see dim "x" */
104 err = ncmpi_inq_dimid(ncid, "xx", &dimid3);
105 CHECK_ERR(NC_EBADDIM)
106 }
107
108 err = ncmpi_close(ncid); ERR
109
110 /* Test inconsistency on dimension size ----------------------------------*/
111 err = ncmpi_create(comm, filename, cmode, info, &ncid); ERR
112 if (rank == 0)
113 err = ncmpi_def_dim(ncid, "x", 99, &dimid1);
114 else
115 err = ncmpi_def_dim(ncid, "x", 100, &dimid1);
116 if (safe_mode)
117 CHECK_ERR(NC_EMULTIDEFINE_DIM_SIZE)
118 else
119 ERR
120
121 err = ncmpi_close(ncid); ERR
122 return nerrs;
123 }
124
125 /*----< test_attr() >---------------------------------------------------------*/
126 static
test_attr(char * filename,int safe_mode)127 int test_attr(char *filename, int safe_mode)
128 {
129 int err, rank, ncid, cmode, nerrs=0;
130 char gattr[128];
131 int int_attr;
132 float flt_attr;
133 MPI_Info info=MPI_INFO_NULL;
134 MPI_Comm comm=MPI_COMM_WORLD;
135
136 MPI_Comm_rank(comm, &rank);
137 cmode = NC_CLOBBER|NC_64BIT_OFFSET;
138
139 /* Test inconsistent global attribute name -------------------------------*/
140 err = ncmpi_create(comm, filename, cmode, info, &ncid); ERR
141 int_attr = 1;
142 sprintf(gattr, "gattr_name.%d",rank);
143 err = ncmpi_put_att_int(ncid, NC_GLOBAL, gattr, NC_INT, 1, &int_attr);
144 if (safe_mode)
145 CHECK_ERR(NC_EMULTIDEFINE_ATTR_NAME)
146 else
147 ERR
148 err = ncmpi_close(ncid); ERR
149
150 /* Test inconsistent global attribute type -------------------------------*/
151 err = ncmpi_create(comm, filename, cmode, info, &ncid); ERR
152 if (rank == 0)
153 err = ncmpi_put_att_int(ncid, NC_GLOBAL, "gatt", NC_INT, 1, &int_attr);
154 else
155 err = ncmpi_put_att_float(ncid, NC_GLOBAL, "gatt", NC_FLOAT, 1, &flt_attr);
156 if (safe_mode)
157 CHECK_ERR(NC_EMULTIDEFINE_ATTR_TYPE)
158 else
159 ERR
160 err = ncmpi_close(ncid); ERR
161
162 /* Test inconsistent global attribute length -----------------------------*/
163 err = ncmpi_create(comm, filename, cmode, info, &ncid); ERR
164 int intv[2]={1,2};
165 if (rank == 0)
166 err = ncmpi_put_att_int(ncid, NC_GLOBAL, "gatt", NC_INT, 2, intv);
167 else
168 err = ncmpi_put_att_int(ncid, NC_GLOBAL, "gatt", NC_INT, 1, intv);
169 if (safe_mode)
170 CHECK_ERR(NC_EMULTIDEFINE_ATTR_LEN)
171 else
172 ERR
173 err = ncmpi_close(ncid); ERR
174
175 /* Test inconsistent global attribute length -----------------------------*/
176 err = ncmpi_create(comm, filename, cmode, info, &ncid); ERR
177 if (rank == 0) intv[1]=3;
178 err = ncmpi_put_att_int(ncid, NC_GLOBAL, "gatt", NC_INT, 2, intv);
179 if (safe_mode)
180 CHECK_ERR(NC_EMULTIDEFINE_ATTR_VAL)
181 else
182 ERR
183 err = ncmpi_close(ncid); ERR
184
185 return nerrs;
186 }
187
188 /*----< test_var() >----------------------------------------------------------*/
189 static
test_var(char * filename,int safe_mode)190 int test_var(char *filename, int safe_mode)
191 {
192 int err, rank, ncid, cmode, nerrs=0;
193 int dimid[3], varid1, int_attr;
194 float flt_attr;
195 char name[128], var_attr[128];
196 MPI_Info info=MPI_INFO_NULL;
197 MPI_Comm comm=MPI_COMM_WORLD;
198
199 MPI_Comm_rank(comm, &rank);
200 cmode = NC_CLOBBER|NC_64BIT_OFFSET;
201
202 /* Test inconsistent global attribute name -------------------------------*/
203 err = ncmpi_create(comm, filename, cmode, info, &ncid); ERR
204 err = ncmpi_def_dim(ncid, "dim1", NC_UNLIMITED, &dimid[0]); ERR
205 err = ncmpi_def_var(ncid, "var1", NC_INT, 1, dimid, &varid1); ERR
206 int_attr = 1;
207 sprintf(var_attr, "var_attr_name.%d",rank);
208 err = ncmpi_put_att_int(ncid, varid1, var_attr, NC_INT, 1, &int_attr);
209 if (safe_mode)
210 CHECK_ERR(NC_EMULTIDEFINE_ATTR_NAME)
211 else
212 ERR
213 err = ncmpi_close(ncid); ERR
214
215 /* Test inconsistent global attribute type -------------------------------*/
216 err = ncmpi_create(comm, filename, cmode, info, &ncid); ERR
217 err = ncmpi_def_dim(ncid, "dim1", NC_UNLIMITED, &dimid[0]); ERR
218 err = ncmpi_def_var(ncid, "var1", NC_INT, 1, dimid, &varid1); ERR
219 if (rank == 0)
220 err = ncmpi_put_att_int(ncid, varid1, "var_att", NC_INT, 1, &int_attr);
221 else
222 err = ncmpi_put_att_float(ncid, varid1, "var_att", NC_FLOAT, 1, &flt_attr);
223 if (safe_mode)
224 CHECK_ERR(NC_EMULTIDEFINE_ATTR_TYPE)
225 else
226 ERR
227 err = ncmpi_close(ncid); ERR
228
229 /* Test inconsistent global attribute length -----------------------------*/
230 err = ncmpi_create(comm, filename, cmode, info, &ncid); ERR
231 err = ncmpi_def_dim(ncid, "dim1", NC_UNLIMITED, &dimid[0]); ERR
232 err = ncmpi_def_var(ncid, "var1", NC_INT, 1, dimid, &varid1); ERR
233 int intv[2]={1,2};
234 if (rank == 0)
235 err = ncmpi_put_att_int(ncid, varid1, "var_att", NC_INT, 2, intv);
236 else
237 err = ncmpi_put_att_int(ncid, varid1, "var_att", NC_INT, 1, intv);
238 if (safe_mode)
239 CHECK_ERR(NC_EMULTIDEFINE_ATTR_LEN)
240 else
241 ERR
242 err = ncmpi_close(ncid); ERR
243
244 /* Test inconsistent global attribute length -----------------------------*/
245 err = ncmpi_create(comm, filename, cmode, info, &ncid); ERR
246 err = ncmpi_def_dim(ncid, "dim1", NC_UNLIMITED, &dimid[0]); ERR
247 err = ncmpi_def_var(ncid, "var1", NC_INT, 1, dimid, &varid1); ERR
248 if (rank == 0) intv[1]=3;
249 err = ncmpi_put_att_int(ncid, varid1, "var_att", NC_INT, 2, intv);
250 if (safe_mode)
251 CHECK_ERR(NC_EMULTIDEFINE_ATTR_VAL)
252 else
253 ERR
254 err = ncmpi_close(ncid); ERR
255
256 /* Test inconsistent variable name ---------------------------------------*/
257 err = ncmpi_create(comm, filename, cmode, info, &ncid); ERR
258 err = ncmpi_def_dim(ncid, "dim1", NC_UNLIMITED, &dimid[0]); ERR
259 sprintf(name, "var.%d",rank);
260 err = ncmpi_def_var(ncid, name, NC_INT, 1, dimid, &varid1);
261 if (safe_mode)
262 CHECK_ERR(NC_EMULTIDEFINE_VAR_NAME)
263 else
264 ERR
265 err = ncmpi_close(ncid); ERR
266
267 /* Test inconsistent variable ndims --------------------------------------*/
268 err = ncmpi_create(comm, filename, cmode, info, &ncid); ERR
269 err = ncmpi_def_dim(ncid, "dim0", 3, &dimid[0]); ERR
270 err = ncmpi_def_dim(ncid, "dim1", 2, &dimid[1]); ERR
271 if (rank == 0)
272 err = ncmpi_def_var(ncid, "var", NC_FLOAT, 2, dimid, &varid1);
273 else
274 err = ncmpi_def_var(ncid, "var", NC_FLOAT, 1, dimid, &varid1);
275 if (safe_mode)
276 CHECK_ERR(NC_EMULTIDEFINE_VAR_NDIMS)
277 else
278 ERR
279 err = ncmpi_close(ncid); ERR
280
281 /* Test inconsistent variable type ---------------------------------------*/
282 err = ncmpi_create(comm, filename, cmode, info, &ncid); ERR
283 err = ncmpi_def_dim(ncid, "dim1", NC_UNLIMITED, &dimid[0]); ERR
284 if (rank == 0)
285 err = ncmpi_def_var(ncid, "var", NC_INT, 1, dimid, &varid1);
286 else
287 err = ncmpi_def_var(ncid, "var", NC_FLOAT, 1, dimid, &varid1);
288 if (safe_mode)
289 CHECK_ERR(NC_EMULTIDEFINE_VAR_TYPE)
290 else
291 ERR
292 err = ncmpi_close(ncid); ERR
293
294 /* Test inconsistent variable length -------------------------------------*/
295 err = ncmpi_create(comm, filename, cmode, info, &ncid); ERR
296 err = ncmpi_def_dim(ncid, "dim0", 5, &dimid[0]); ERR
297 err = ncmpi_def_dim(ncid, "dim1", 4, &dimid[1]); ERR
298 err = ncmpi_def_dim(ncid, "dim2", 3, &dimid[2]); ERR
299 if (rank == 0)
300 err = ncmpi_def_var(ncid, "var", NC_FLOAT, 2, dimid, &varid1);
301 else
302 err = ncmpi_def_var(ncid, "var", NC_FLOAT, 2, dimid+1, &varid1);
303 if (safe_mode)
304 CHECK_ERR(NC_EMULTIDEFINE_VAR_DIMIDS)
305 else
306 ERR
307 err = ncmpi_close(ncid); ERR
308
309 /* Test inconsistent variable dimension IDs ------------------------------*/
310 err = ncmpi_create(comm, filename, cmode, info, &ncid); ERR
311 err = ncmpi_def_dim(ncid, "Z", 3, &dimid[0]); ERR
312 err = ncmpi_def_dim(ncid, "Y", 3, &dimid[1]); ERR
313 err = ncmpi_def_dim(ncid, "X", 3, &dimid[2]); ERR
314 if (rank == 0)
315 err = ncmpi_def_var(ncid, "var", NC_FLOAT, 2, dimid+1, &varid1);
316 else
317 err = ncmpi_def_var(ncid, "var", NC_FLOAT, 2, dimid, &varid1);
318 if (safe_mode)
319 CHECK_ERR(NC_EMULTIDEFINE_VAR_DIMIDS)
320 else
321 ERR
322
323 err = ncmpi_close(ncid); ERR
324
325 return nerrs;
326 }
327
328 /*----< main() >--------------------------------------------------------------*/
main(int argc,char ** argv)329 int main(int argc, char **argv)
330 {
331 char *filename="testfile.nc", *mode[2] = {"0", "1"};
332 int i, rank, nprocs, verbose, nerrs=0;
333
334 MPI_Init(&argc, &argv);
335 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
336 MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
337
338 if (nprocs < 2) {
339 if (!rank) printf("This program is for running 2 or more processes. Exiting ...\n");
340 MPI_Finalize();
341 return 0;
342 }
343
344 if (argc > 2) {
345 if (!rank) printf("Usage: %s [filename]\n",argv[0]);
346 MPI_Finalize();
347 return 0;
348 }
349 if (argc == 2) filename = argv[1];
350
351 if (rank == 0) {
352 char *cmd_str = (char*)malloc(strlen(argv[0]) + 256);
353 sprintf(cmd_str, "*** TESTING C %s for header consistency", basename(argv[0]));
354 printf("%-66s ------ ", cmd_str);
355 free(cmd_str);
356 }
357
358 verbose = 1;
359 for (i=verbose; i>=0; i--) {
360 /* test with safe mode off and on :
361 * Note even if --enable-debug is set at configure time, safe mode
362 * can still be disabled by setting the environment variable
363 * PNETCDF_SAFE_MODE to 0.
364 */
365 setenv("PNETCDF_SAFE_MODE", mode[i], 1);
366 nerrs += test_open_mode(filename, i);
367
368 nerrs += test_dim(filename, i);
369
370 nerrs += test_attr(filename, i);
371
372 nerrs += test_var(filename, i);
373 }
374
375 MPI_Offset malloc_size, sum_size;
376 int err = ncmpi_inq_malloc_size(&malloc_size);
377 if (err == NC_NOERR) {
378 MPI_Reduce(&malloc_size, &sum_size, 1, MPI_OFFSET, MPI_SUM, 0, MPI_COMM_WORLD);
379 if (rank == 0 && sum_size > 0)
380 printf("heap memory allocated by PnetCDF internally has %lld bytes yet to be freed\n",
381 sum_size);
382 }
383
384 MPI_Allreduce(MPI_IN_PLACE, &nerrs, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
385 if (rank == 0) {
386 if (nerrs) printf(FAIL_STR,nerrs);
387 else printf(PASS_STR);
388 }
389
390 MPI_Finalize();
391 return 0;
392 }
393
394