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