test-driver.c
author Kristian H?gsberg <krh@jiraiya.boston.redhat.com>
Wed Apr 09 02:41:03 2008 -0400 (2008-04-09)
changeset 211 cf0ca962262b
parent 208 7b460017c221
child 223 e1d7ed03e5d9
child 230 c1e2aed8dd07
permissions -rw-r--r--
Use the cpio headers instead of the rpm headers when unpacking.

The files in the cpio payload doesn't actually follow the file order
in the rpm headers, so we need to decode the cpio header and use the
information there.
     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <stdarg.h>
     4 #include <unistd.h>
     5 #include <fcntl.h>
     6 #include <errno.h>
     7 #include <expat.h>
     8 
     9 #include "razor.h"
    10 
    11 #define XML_BUFFER_SIZE 4096
    12 
    13 static void
    14 parse_xml_file(const char *filename,
    15 	       XML_StartElementHandler start,
    16 	       XML_EndElementHandler end,
    17 	       void *data)
    18 {
    19 	XML_Parser parser;
    20 	char *buffer;
    21 	int fd, len, err;
    22 
    23 	parser = XML_ParserCreate(NULL);
    24 	XML_SetElementHandler(parser, start, end);
    25 	XML_SetUserData(parser, data);
    26 
    27 	fd = open(filename, O_RDONLY);
    28 	if (fd < 0) {
    29 		fprintf(stderr, "failed to open %s: %m\n", filename);
    30 		exit(-1);
    31 	}
    32 
    33 	while (1) {
    34 		buffer = XML_GetBuffer(parser, XML_BUFFER_SIZE);
    35 		len = read(fd, buffer, XML_BUFFER_SIZE);
    36 		if (len == 0)
    37 			break;
    38 		err = XML_ParseBuffer(parser, len, len == 0);
    39 		if (err == XML_STATUS_ERROR) {
    40 			fprintf(stderr, "parse error at line %lu:\n%s\n",
    41 				XML_GetCurrentLineNumber(parser),
    42 				XML_ErrorString(XML_GetErrorCode(parser)));
    43 			exit(-1);
    44 		}
    45 	}
    46 
    47 	if (fd < 0) {
    48 		fprintf(stderr, "read: %m\n");
    49 		exit(-1);
    50 	}
    51 
    52 	close(fd);
    53 }
    54 
    55 struct test_context {
    56 	struct razor_set *system_set, *repo_set, *result_set;
    57 
    58 	struct razor_importer *importer;
    59 	struct razor_set **importer_set;
    60 
    61 	struct razor_transaction *trans;
    62 
    63 	char *install_pkgs[3], *remove_pkgs[3];
    64 	int n_install_pkgs, n_remove_pkgs;
    65 
    66 	int unsat;
    67 	int in_result;
    68 
    69 	int debug, errors;
    70 };
    71 
    72 static void
    73 get_atts(const char **atts, ...)
    74 {
    75 	va_list ap;
    76 	const char *name, **ptr;
    77 	int i;
    78 
    79 	va_start(ap, atts);
    80 	while (name = va_arg(ap, const char *), name != NULL) {
    81 		ptr = va_arg(ap, const char **);
    82 		*ptr = NULL;
    83 		for (i = 0; atts[i]; i += 2) {
    84 			if (strcmp(atts[i], name) == 0)
    85 				*ptr = atts[i + 1];
    86 		}
    87 	}
    88 	va_end(ap);
    89 }
    90 
    91 static enum razor_version_relation
    92 parse_relation (const char *rel_str)
    93 {
    94 	if (!rel_str)
    95 		return -1;
    96 	if (rel_str[0] == 'L')
    97 		return rel_str[1] == 'E' ? RAZOR_VERSION_LESS_OR_EQUAL : RAZOR_VERSION_LESS;
    98 	else if (rel_str[0] == 'G')
    99 		return rel_str[1] == 'E' ? RAZOR_VERSION_GREATER_OR_EQUAL : RAZOR_VERSION_GREATER;
   100 	else if (rel_str[0] == 'E' || rel_str[1] == 'Q')
   101 		return RAZOR_VERSION_EQUAL;
   102 	else
   103 		return -1;
   104 }
   105 
   106 static void
   107 start_test(struct test_context *ctx, const char **atts)
   108 {
   109 	const char *name = NULL;
   110 
   111 	get_atts(atts, "name", &name, NULL);
   112 	if (!name) {
   113 		fprintf(stderr, "Test with no name\n");
   114 		exit(1);
   115 	}
   116 	printf("%s\n", name);
   117 }
   118 
   119 static void
   120 end_test(struct test_context *ctx)
   121 {
   122 	if (ctx->system_set) {
   123 		razor_set_destroy(ctx->system_set);
   124 		ctx->system_set = NULL;
   125 	}
   126 	if (ctx->repo_set) {
   127 		razor_set_destroy(ctx->repo_set);
   128 		ctx->repo_set = NULL;
   129 	}
   130 	if (ctx->result_set) {
   131 		razor_set_destroy(ctx->result_set);
   132 		ctx->result_set = NULL;
   133 	}
   134 	if (ctx->trans) {
   135 		razor_transaction_destroy(ctx->trans);
   136 		ctx->trans = NULL;
   137 	}
   138 }
   139 
   140 static void
   141 start_set(struct test_context *ctx, const char **atts)
   142 {
   143 	const char *name = NULL;
   144 
   145 	ctx->importer = razor_importer_new();
   146 	get_atts(atts, "name", &name, NULL);
   147 	if (!name)
   148 		ctx->importer_set = &ctx->result_set;
   149 	else if (!strcmp(name, "system"))
   150 		ctx->importer_set = &ctx->system_set;
   151 	else if (!strcmp(name, "repo"))
   152 		ctx->importer_set = &ctx->repo_set;
   153 	else {
   154 		fprintf(stderr, "  bad set name '%s'\n", name);
   155 		exit(1);
   156 	}
   157 }
   158 
   159 static void
   160 end_set(struct test_context *ctx)
   161 {
   162 	*ctx->importer_set = razor_importer_finish(ctx->importer);
   163 	ctx->importer = NULL;
   164 }
   165 
   166 static void
   167 start_package(struct test_context *ctx, const char **atts)
   168 {
   169 	const char *name = NULL, *version = NULL, *arch = NULL;
   170 
   171 	get_atts(atts, "name", &name,
   172 		 "version", &version,
   173 		 "arch", &arch,
   174 		 NULL);
   175 
   176 	if (!name) {
   177 		fprintf(stderr, "  package with no name\n");
   178 		exit(1);
   179 	}
   180 
   181 	razor_importer_begin_package(ctx->importer, name, version, arch);
   182 	razor_importer_add_property(ctx->importer, name,
   183 				    RAZOR_VERSION_EQUAL, version,
   184 				    RAZOR_PROPERTY_PROVIDES);
   185 }
   186 
   187 static void
   188 end_package(struct test_context *ctx)
   189 {
   190 	razor_importer_finish_package(ctx->importer);
   191 }
   192 
   193 static void
   194 add_property(struct test_context *ctx, enum razor_property_type type, const char *name, enum razor_version_relation rel, const char *version)
   195 {
   196 	razor_importer_add_property(ctx->importer, name,
   197 				    rel, version, type);
   198 }
   199 
   200 static void
   201 check_unsatisfiable_property(struct test_context *ctx,
   202 			     enum razor_property_type type,
   203 			     const char *name,
   204 			     enum razor_version_relation rel,
   205 			     const char *version)
   206 {
   207 	if (!version)
   208 		version = "";
   209 
   210 	if (razor_transaction_unsatisfied_property(ctx->trans,
   211 						   name, rel, version))
   212 		return;
   213 
   214 	fprintf(stderr, "  didn't get unsatisfiable '%s %s %s'\n",
   215 		name, razor_version_relations[rel], version);
   216 	ctx->errors++;
   217 }
   218 
   219 static void
   220 start_property(struct test_context *ctx, enum razor_property_type type, const char **atts)
   221 {
   222 	const char *name = NULL, *rel_str = NULL, *version = NULL;
   223 	enum razor_version_relation rel;
   224 
   225 	get_atts(atts, "name", &name, "relation", &rel_str, "version", &version, NULL);
   226 	if (name == NULL) {
   227 		fprintf(stderr, "  no name specified for property\n");
   228 		exit(1);
   229 	}
   230 	if (version) {
   231 		rel = parse_relation(rel_str);
   232 		if (rel == -1) {
   233 			fprintf(stderr, "  bad or missing version relation for property %s\n", name);
   234 			exit(1);
   235 		}
   236 	} else
   237 		rel = RAZOR_VERSION_EQUAL;
   238 	
   239 	if (ctx->unsat)
   240 		check_unsatisfiable_property(ctx, type, name, rel, version);
   241 	else
   242 		add_property(ctx, type, name, rel, version);
   243 }
   244 
   245 static void
   246 start_transaction(struct test_context *ctx, const char **atts)
   247 {
   248 	ctx->n_install_pkgs = 0;
   249 	ctx->n_remove_pkgs = 0;
   250 }
   251 
   252 static void
   253 end_transaction(struct test_context *ctx)
   254 {
   255 	struct razor_package *pkg;
   256 	int errors, i;
   257 
   258 	ctx->trans = razor_transaction_create(ctx->system_set, ctx->repo_set);
   259 	for (i = 0; i < ctx->n_install_pkgs; i++) {
   260 		pkg = razor_set_get_package(ctx->repo_set,
   261 					    ctx->install_pkgs[i]);
   262 		razor_transaction_install_package(ctx->trans, pkg);
   263 	}		
   264 	for (i = 0; i < ctx->n_remove_pkgs; i++) {
   265 		pkg = razor_set_get_package(ctx->repo_set,
   266 					    ctx->remove_pkgs[i]);
   267 		razor_transaction_remove_package(ctx->trans, pkg);
   268 	}		
   269 
   270 	errors = razor_transaction_resolve(ctx->trans);
   271 	printf("\n");
   272 
   273 	while (ctx->n_install_pkgs--)
   274 		free(ctx->install_pkgs[ctx->n_install_pkgs]);
   275 	while (ctx->n_remove_pkgs--)
   276 		free(ctx->remove_pkgs[ctx->n_remove_pkgs]);
   277 
   278 	if (!errors) {
   279 		struct razor_set *new;
   280 		new = razor_transaction_finish(ctx->trans);
   281 		ctx->system_set = new;
   282 	}
   283 }
   284 
   285 static void
   286 start_install_or_update(struct test_context *ctx, const char **atts)
   287 {
   288 	const char *name = NULL;
   289 
   290 	get_atts(atts, "name", &name, NULL);
   291 	if (!name) {
   292 		fprintf(stderr, "  install/update with no name\n");
   293 		exit(1);
   294 	}
   295 
   296 	ctx->install_pkgs[ctx->n_install_pkgs++] = strdup(name);
   297 }
   298 
   299 static void
   300 start_remove(struct test_context *ctx, const char **atts)
   301 {
   302 	const char *name = NULL;
   303 
   304 	get_atts(atts, "name", &name, NULL);
   305 	if (!name) {
   306 		fprintf(stderr, "  remove with no name\n");
   307 		exit(1);
   308 	}
   309 
   310 	ctx->remove_pkgs[ctx->n_remove_pkgs++] = strdup(name);
   311 }
   312 
   313 static void
   314 start_result(struct test_context *ctx, const char **atts)
   315 {
   316 	ctx->in_result = 1;
   317 }
   318 
   319 static void
   320 diff_callback(const char *name,
   321 	      const char *old_version,
   322 	      const char *new_version,
   323 	      const char *arch,
   324 	      void *data)
   325 {
   326 	struct test_context *ctx = data;
   327 
   328 	ctx->errors++;
   329 	if (old_version) {
   330 		fprintf(stderr, "  result set should not contain %s %s\n",
   331 			name, old_version);
   332 	} else {
   333 		fprintf(stderr, "  result set should contain %s %s\n",
   334 			name, new_version);
   335 	}
   336 }
   337 
   338 static void
   339 end_result(struct test_context *ctx)
   340 {
   341 	ctx->in_result = 0;
   342 
   343 	if (ctx->result_set) {
   344 		if (!ctx->system_set)
   345 			ctx->system_set = razor_set_create();
   346 		razor_set_diff(ctx->system_set, ctx->result_set,
   347 			       diff_callback, ctx);
   348 	}
   349 }
   350 
   351 static void
   352 start_unsatisfiable(struct test_context *ctx, const char **atts)
   353 {
   354 	if (ctx->result_set) {
   355 		fprintf(stderr, "Expected to fail, but didn't\n");
   356 		exit(1);
   357 	}
   358 
   359 	ctx->unsat = 1;
   360 }
   361 
   362 static void
   363 end_unsatisfiable(struct test_context *ctx)
   364 {
   365 	ctx->unsat = 0;
   366 }
   367 
   368 static void
   369 start_test_element(void *data, const char *element, const char **atts)
   370 {
   371 	struct test_context *ctx = data;
   372 
   373 	if (strcmp(element, "tests") == 0) {
   374 		;
   375 	} else if (strcmp(element, "test") == 0) {
   376 		start_test(ctx, atts);
   377 	} else if (strcmp(element, "set") == 0) {
   378 		start_set(ctx, atts);
   379 	} else if (strcmp(element, "transaction") == 0) {
   380 		start_transaction(ctx, atts);
   381 	} else if (strcmp(element, "install") == 0) {
   382 		start_install_or_update(ctx, atts);
   383 	} else if (strcmp(element, "install") == 0) {
   384 		start_install_or_update(ctx, atts);
   385 	} else if (strcmp(element, "remove") == 0) {
   386 		start_remove(ctx, atts);
   387 	} else if (strcmp(element, "result") == 0) {
   388 		start_result(ctx, atts);
   389 	} else if (strcmp(element, "unsatisfiable") == 0) {
   390 		start_unsatisfiable(ctx, atts);
   391 	} else if (strcmp(element, "package") == 0) {
   392 		start_package(ctx, atts);
   393 	} else if (strcmp(element, "requires") == 0) {
   394 		start_property(ctx, RAZOR_PROPERTY_REQUIRES, atts);
   395 	} else if (strcmp(element, "provides") == 0) {
   396 		start_property(ctx, RAZOR_PROPERTY_PROVIDES, atts);
   397 	} else if (strcmp(element, "conflicts") == 0) {
   398 		start_property(ctx, RAZOR_PROPERTY_CONFLICTS, atts);
   399 	} else if (strcmp(element, "obsoletes") == 0) {
   400 		start_property(ctx, RAZOR_PROPERTY_OBSOLETES, atts);
   401 	} else {
   402 		fprintf(stderr, "Unrecognized element '%s'\n", element);
   403 		exit(1);
   404 	}
   405 }
   406 
   407 static void
   408 end_test_element (void *data, const char *element)
   409 {
   410 	struct test_context *ctx = data;
   411 
   412 	if (strcmp(element, "test") == 0) {
   413 		end_test(ctx);
   414 	} else if (strcmp(element, "set") == 0) {
   415 		end_set(ctx);
   416 	} else if (strcmp(element, "package") == 0) {
   417 		end_package(ctx);
   418 	} else if (strcmp(element, "transaction") == 0) {
   419 		end_transaction(ctx);
   420 	} else if (strcmp(element, "result") == 0) {
   421 		end_result(ctx);
   422 	} else if (strcmp(element, "unsatisfiable") == 0) {
   423 		end_unsatisfiable(ctx);
   424 	}
   425 }
   426 
   427 int main(int argc, char *argv[])
   428 {
   429 	struct test_context ctx;
   430 	const char *test_file;
   431 
   432 	memset(&ctx, 0, sizeof ctx);
   433 
   434 	if (argc > 3) {
   435 		fprintf(stderr, "usage: %s [-d] [TESTS-FILE]\n", argv[0]);
   436 		exit(-1);			
   437 	}
   438 
   439 	if (argc >= 2 && !strcmp (argv[1], "-d")) {
   440 		ctx.debug = 1;
   441 		argc--;
   442 		argv++;
   443 	}
   444 	if (argc == 2)
   445 		test_file = argv[1];
   446 	else
   447 		test_file = "test.xml";
   448 
   449 	parse_xml_file(test_file, start_test_element, end_test_element, &ctx);
   450 
   451 	if (ctx.errors) {
   452 		fprintf(stderr, "\n%d errors\n", ctx.errors);
   453 		return 1;
   454 	} else
   455 		return 0;
   456 }