1 /*********************************************************************
2  *
3  *  Copyright (C) 2014, Northwestern University and Argonne National Laboratory
4  *  See COPYRIGHT notice in top-level directory.
5  *
6  *********************************************************************/
7 /* $Id: modes.c 2744 2016-12-28 16:25:22Z wkliao $ */
8 
9 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
10  * This program tests if the correct error codes are returns given various
11  * create/open modes.
12  *
13  * NC_EINVAL_CMODE should be returned when creating a file using
14  * comde with both NC_64BIT_OFFSET & NC_64BIT_DATA flags set.
15  *
16  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
17 
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h> /* strcpy() */
21 #include <libgen.h> /* basename() */
22 #include <unistd.h> /* unlink(), access() */
23 #include <mpi.h>
24 #include <pnetcdf.h>
25 
26 #include <testutils.h>
27 
28 #define ERR {if(err!=NC_NOERR)printf("Error at line=%d: %s\n", __LINE__, ncmpi_strerror(err));}
29 
30 #define EXPECT_ERR(err_no) \
31     if (err != err_no) { \
32         nerrs++; \
33         printf("Error at line %d: expect error code %s but got %s\n", \
34                __LINE__,nc_err_code_name(err_no),nc_err_code_name(err)); \
35     }
36 
37 #define EXPECT_ERR2(err_no1, err_no2) \
38     if (err != err_no1 && err != err_no2) { \
39         nerrs++; \
40         printf("Error at line %d: expect error code %s but got %s\n", \
41                __LINE__,nc_err_code_name(err_no1),nc_err_code_name(err)); \
42     }
43 
44 static
check_modes(char * filename)45 int check_modes(char *filename)
46 {
47     int rank, err, nerrs=0;
48     int ncid, cmode;
49 
50     MPI_Comm_rank(MPI_COMM_WORLD, &rank);
51 
52     /* delete the file and ignore error */
53     unlink(filename);
54     MPI_Barrier(MPI_COMM_WORLD);
55 
56     /* create a new file and test various cmodes ----------------------------*/
57     cmode = NC_CLOBBER;
58 
59     /* It is illegal to use both NC_64BIT_OFFSET and NC_64BIT_DATA together */
60     cmode |= NC_64BIT_OFFSET | NC_64BIT_DATA;
61 
62     err = ncmpi_create(MPI_COMM_WORLD, filename, cmode, MPI_INFO_NULL, &ncid);
63     EXPECT_ERR(NC_EINVAL_CMODE)
64 
65     /* The file should not be created */
66     if (rank == 0) {
67         if (access(filename, F_OK) == 0) {
68             printf("Error at line %d: file (%s) should not be created\n",
69                    __LINE__, filename);
70             nerrs++;
71             /* delete the file and ignore error */
72             unlink(filename);
73         }
74         /* else : file does not exist */
75     }
76     MPI_Barrier(MPI_COMM_WORLD);
77 
78     /* Collectively opening a non-existing file for read, expect error code
79      * NC_ENOENT on all processes */
80     err = ncmpi_open(MPI_COMM_WORLD, filename, NC_NOWRITE, MPI_INFO_NULL, &ncid);
81     /* older version of OpenMPI and MPICH may return MPI_ERR_IO instead of
82      * MPI_ERR_NO_SUCH_FILE */
83     EXPECT_ERR2(NC_ENOENT, NC_EFILE)
84 
85     /* The file should not be created */
86     if (rank == 0) {
87         if (access(filename, F_OK) == 0) {
88             printf("Error at line %d: file (%s) should not be created\n",
89                    __LINE__, filename);
90             nerrs++;
91             /* delete the file and ignore error */
92             unlink(filename);
93         }
94         /* else : file does not exist */
95     }
96     MPI_Barrier(MPI_COMM_WORLD);
97 
98     /* Collectively opening a non-existing file for write, expect error code
99      * NC_ENOENT on all processes */
100     err = ncmpi_open(MPI_COMM_WORLD, filename, NC_WRITE, MPI_INFO_NULL, &ncid);
101     /* older version of OpenMPI and MPICH may return MPI_ERR_IO instead of
102      * MPI_ERR_NO_SUCH_FILE */
103     EXPECT_ERR2(NC_ENOENT, NC_EFILE)
104 
105     /* The file should not be created */
106     if (rank == 0) {
107         if (access(filename, F_OK) == 0) {
108             printf("Error at line %d: file (%s) should not be created\n",
109                    __LINE__, filename);
110             nerrs++;
111             /* delete the file and ignore error */
112             unlink(filename);
113         }
114         /* else : file does not exist */
115     }
116     MPI_Barrier(MPI_COMM_WORLD);
117 
118     return nerrs;
119 }
120 
main(int argc,char ** argv)121 int main(int argc, char** argv)
122 {
123     char filename[256];
124     int rank, err, nerrs=0;
125 
126     MPI_Init(&argc, &argv);
127     MPI_Comm_rank(MPI_COMM_WORLD, &rank);
128 
129     if (argc > 2) {
130         if (!rank) printf("Usage: %s [filename]\n",argv[0]);
131         MPI_Finalize();
132         return 0;
133     }
134     if (argc == 2) snprintf(filename, 256, "%s", argv[1]);
135     else           strcpy(filename, "testfile.nc");
136     MPI_Bcast(filename, 256, MPI_CHAR, 0, MPI_COMM_WORLD);
137 
138     if (rank == 0) {
139         char *cmd_str = (char*)malloc(strlen(argv[0]) + 256);
140         sprintf(cmd_str, "*** TESTING C   %s for file create/open modes ", basename(argv[0]));
141         printf("%-66s ------ ", cmd_str); fflush(stdout);
142         free(cmd_str);
143     }
144 
145     /* test under safe mode enabled */
146     setenv("PNETCDF_SAFE_MODE", "1", 1);
147     nerrs += check_modes(filename);
148 
149     /* test under safe mode disabled */
150     setenv("PNETCDF_SAFE_MODE", "0", 1);
151     nerrs += check_modes(filename);
152 
153     /* check if PnetCDF freed all internal malloc */
154     MPI_Offset malloc_size, sum_size;
155     err = ncmpi_inq_malloc_size(&malloc_size);
156     if (err == NC_NOERR) {
157         MPI_Reduce(&malloc_size, &sum_size, 1, MPI_OFFSET, MPI_SUM, 0, MPI_COMM_WORLD);
158         if (rank == 0 && sum_size > 0)
159             printf("heap memory allocated by PnetCDF internally has %lld bytes yet to be freed\n",
160                    sum_size);
161     }
162 
163     MPI_Allreduce(MPI_IN_PLACE, &nerrs, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD);
164     if (rank == 0) {
165         if (nerrs) printf(FAIL_STR,nerrs);
166         else       printf(PASS_STR);
167     }
168 
169     MPI_Finalize();
170     return 0;
171 }
172 
173