Add ABI compliance test. To run it, run 'ninja test-abi'
authorJonathan Dieter <jdieter@gmail.com>
Fri, 8 Jun 2018 07:08:17 +0000 (10:08 +0300)
committerJonathan Dieter <jdieter@gmail.com>
Fri, 8 Jun 2018 07:16:01 +0000 (10:16 +0300)
Signed-off-by: Jonathan Dieter <jdieter@gmail.com>
.gitignore
test/abi.sh [new file with mode: 0755]
test/abi/stable/libzck.so.0.0.1 [new file with mode: 0755]
test/abi/stable/zck.h [new file with mode: 0644]
test/meson.build
test/new_abi.sh [new file with mode: 0755]

index 378eac25d311703f3f2cd456d8036da525cd0366..7e6710b8e56dadf2a0226e6f0da1095b0f27ce8e 100644 (file)
@@ -1 +1,3 @@
 build
+test/abi/new
+test/abi/stable/ABI.dump
diff --git a/test/abi.sh b/test/abi.sh
new file mode 100755 (executable)
index 0000000..0a94f39
--- /dev/null
@@ -0,0 +1,34 @@
+#!/bin/sh
+cd "$(dirname "$0")"
+
+if [ ! -e ../build/src/lib/libzck.so.*.*.* ]; then
+    echo "No library exists"
+    exit 1
+fi
+
+# Copy latest build to abi/new and remove softlinks
+rm abi/new -rf
+mkdir -p abi/new
+cp -a ../build/src/lib/libzck.so.* abi/new
+cp -a ../include/zck.h abi/new
+find abi -type l -delete
+
+# Redump abi/stable
+cd abi/stable
+abi-dumper libzck.so.* -lver `cat zck.h | grep ZCK_VERSION | head -n 1 | awk '{ print $3 }' | sed s/\"//g`
+if [ "$?" -ne 0 ]; then
+    exit 1
+fi
+
+# Dump abi/new
+cd ../new
+abi-dumper libzck.so.* -lver `cat zck.h | grep ZCK_VERSION | head -n 1 | awk '{ print $3 }' | sed s/\"//g`
+if [ "$?" -ne 0 ]; then
+    exit 1
+fi
+cd ../../
+
+# Remove any old reports and generate new abi compliance report
+rm compat_reports -rf
+abi-compliance-checker -l zchunk -old abi/stable/ABI.dump -new abi/new/ABI.dump
+exit $?
diff --git a/test/abi/stable/libzck.so.0.0.1 b/test/abi/stable/libzck.so.0.0.1
new file mode 100755 (executable)
index 0000000..8d1722a
Binary files /dev/null and b/test/abi/stable/libzck.so.0.0.1 differ
diff --git a/test/abi/stable/zck.h b/test/abi/stable/zck.h
new file mode 100644 (file)
index 0000000..2892b62
--- /dev/null
@@ -0,0 +1,332 @@
+#ifndef ZCK_H
+#define ZCK_H
+
+#define ZCK_VERSION "0.6.2"
+#define ZCK_VER_MAJOR 0
+#define ZCK_VER_MINOR 6
+#define ZCK_VER_REVISION 2
+#define ZCK_VER_SUBREVISION 0
+
+#define True 1
+#define False 0
+
+typedef enum zck_hash {
+    ZCK_HASH_SHA1,
+    ZCK_HASH_SHA256,
+    ZCK_HASH_UNKNOWN
+} zck_hash;
+
+typedef enum zck_comp {
+    ZCK_COMP_NONE,
+    ZCK_COMP_GZIP, /* Not implemented yet */
+    ZCK_COMP_ZSTD
+} zck_comp;
+
+typedef enum zck_ioption {
+    ZCK_HASH_FULL_TYPE = 0,     /* Set full file hash type, using zck_hash */
+    ZCK_HASH_CHUNK_TYPE,        /* Set chunk hash type using zck_hash */
+    ZCK_VAL_HEADER_HASH_TYPE,   /* Set what the header hash type *should* be */
+    ZCK_VAL_HEADER_LENGTH,      /* Set what the header length *should* be */
+    ZCK_COMP_TYPE = 100,        /* Set compression type using zck_comp */
+    ZCK_ZSTD_COMP_LEVEL = 1000  /* Set zstd compression level */
+} zck_ioption;
+
+typedef enum zck_soption {
+    ZCK_VAL_HEADER_DIGEST = 0,  /* Set what the header hash *should* be */
+    ZCK_COMP_DICT = 100         /* Set compression dictionary */
+} zck_soption;
+
+typedef enum zck_log_type {
+    ZCK_LOG_DEBUG,
+    ZCK_LOG_INFO,
+    ZCK_LOG_WARNING,
+    ZCK_LOG_ERROR,
+    ZCK_LOG_NONE
+} zck_log_type;
+
+typedef struct zckCtx zckCtx;
+typedef struct zckHash zckHash;
+
+/* Contains an index item pointing to a chunk */
+typedef struct zckIndexItem {
+    char *digest;
+    int digest_size;
+    int valid;
+    size_t start;
+    size_t comp_length;
+    size_t length;
+    struct zckIndexItem *next;
+} zckIndexItem;
+
+/* Contains everything about an index and a pointer to the first index item */
+typedef struct zckIndex {
+    size_t count;
+    size_t length;
+    int hash_type;
+    size_t digest_size;
+    zckIndexItem *first;
+} zckIndex;
+
+/* Contains a single range */
+typedef struct zckRangeItem {
+    size_t start;
+    size_t end;
+    struct zckRangeItem *next;
+    struct zckRangeItem *prev;
+} zckRangeItem;
+
+/* Contains a series of ranges, information about them, a link to the first
+ * range item, and an index describing what information is in the ranges */
+typedef struct zckRange {
+    unsigned int count;
+    zckRangeItem *first;
+    zckIndex index;
+} zckRange;
+
+/*******************************************************************
+ * Reading a zchunk file
+ *******************************************************************/
+/* Initialize zchunk for reading */
+zckCtx *zck_init_read (int src_fd)
+    __attribute__ ((warn_unused_result));
+/* Decompress dst_size bytes from zchunk file to dst, while verifying hashes */
+ssize_t zck_read(zckCtx *zck, char *dst, size_t dst_size)
+    __attribute__ ((warn_unused_result));
+
+
+/*******************************************************************
+ * Writing a zchunk file
+ *******************************************************************/
+/* Initialize zchunk for writing */
+zckCtx *zck_init_write (int dst_fd)
+    __attribute__ ((warn_unused_result));
+/* Compress data src of size src_size, and write to zchunk file
+ * Due to the nature of zchunk files and how they are built, no data will
+ * actually appear in the zchunk file until zck_close() is called */
+ssize_t zck_write(zckCtx *zck, const char *src, const size_t src_size)
+    __attribute__ ((warn_unused_result));
+/* Create a chunk boundary */
+ssize_t zck_end_chunk(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+
+
+/*******************************************************************
+ * Common functions for finishing a zchunk file
+ *******************************************************************/
+/* Close a zchunk file so it may no longer be read from or written to. The
+ * context still contains information about the file */
+int zck_close(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+/* Free a zchunk context.  You must pass the address of the context, and the
+ * context will automatically be set to NULL after it is freed */
+void zck_free(zckCtx **zck);
+
+
+/*******************************************************************
+ * Options
+ *******************************************************************/
+/* Set string option */
+int zck_set_soption(zckCtx *zck, zck_soption option, const char *value,
+                    size_t length)
+    __attribute__ ((warn_unused_result));
+/* Set integer option */
+int zck_set_ioption(zckCtx *zck, zck_ioption option, ssize_t value)
+    __attribute__ ((warn_unused_result));
+
+
+/*******************************************************************
+ * Miscellaneous utilities
+ *******************************************************************/
+/* Set logging level */
+void zck_set_log_level(zck_log_type ll);
+/* Validate the chunk and data checksums for the current file.
+ * Returns -1 for error, 0 for invalid checksum and 1 for valid checksum */
+int zck_validate_checksums(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+/* Validate just the data checksum for the current file */
+int zck_validate_data_checksum(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+/* Go through file and mark valid chunks as valid */
+int zck_find_valid_chunks(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+
+/* Get a zckRange of ranges that need to still be downloaded.
+ * max_ranges is the maximum number of ranges supported in a single request
+ *     by the server.  If the server supports unlimited ranges, set to -1
+ * Returns NULL if there's an error */
+zckRange *zck_get_dl_range(zckCtx *zck, int max_ranges)
+    __attribute__ ((warn_unused_result));
+/* Get a string representation of a zckRange */
+char *zck_get_range_char(zckRange *range)
+    __attribute__ ((warn_unused_result));
+/* Get file descriptor attached to zchunk context */
+int zck_get_fd(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+
+/* Return number of missing chunks (-1 if error) */
+int zck_missing_chunks(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+/* Return number of failed chunks (-1 if error) */
+int zck_failed_chunks(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+/* Reset failed chunks to become missing */
+void zck_reset_failed_chunks(zckCtx *zck);
+
+/*******************************************************************
+ * The functions should be all you need to read and write a zchunk
+ * file.  After this point are advanced functions with an unstable
+ * API, so use them with care.
+ *******************************************************************/
+
+
+/*******************************************************************
+ * Advanced miscellaneous zchunk functions
+ *******************************************************************/
+/* Initialize zchunk context */
+zckCtx *zck_create()
+    __attribute__ ((warn_unused_result));
+/* Get lead length */
+ssize_t zck_get_lead_length(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+/* Get header length (lead + preface + index + sigs) */
+ssize_t zck_get_header_length(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+/* Get data length */
+ssize_t zck_get_data_length(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+/* Get file length */
+ssize_t zck_get_length(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+/* Get index digest */
+char *zck_get_header_digest(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+/* Get data digest */
+char *zck_get_data_digest(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+
+
+/*******************************************************************
+ * Advanced compression functions
+ *******************************************************************/
+/* Get name of compression type */
+const char *zck_comp_name_from_type(int comp_type)
+    __attribute__ ((warn_unused_result));
+/* Initialize compression.  Compression type and parameters *must* be done
+ * before this is called */
+
+
+/*******************************************************************
+ * Advanced zchunk reading functions
+ *******************************************************************/
+/* Initialize zchunk for reading using advanced options */
+zckCtx *zck_init_adv_read (int src_fd)
+    __attribute__ ((warn_unused_result));
+/* Read zchunk lead */
+int zck_read_lead(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+/* Read zchunk header */
+int zck_read_header(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+
+
+/*******************************************************************
+ * Indexes
+ *******************************************************************/
+/* Get index count */
+ssize_t zck_get_index_count(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+/* Get index */
+zckIndex *zck_get_index(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+/* Get chunk digest */
+char *zck_get_chunk_digest(zckIndexItem *item)
+    __attribute__ ((warn_unused_result));
+
+
+/*******************************************************************
+ * Advanced hash functions
+ *******************************************************************/
+/* Get overall hash type */
+int zck_get_full_hash_type(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+/* Get digest size of overall hash type */
+ssize_t zck_get_full_digest_size(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+/* Get chunk hash type */
+int zck_get_chunk_hash_type(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+/* Get digest size of chunk hash type */
+ssize_t zck_get_chunk_digest_size(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+/* Get name of hash type */
+const char *zck_hash_name_from_type(int hash_type)
+    __attribute__ ((warn_unused_result));
+
+
+
+/*******************************************************************
+ * Downloading (should this go in a separate header and library?)
+ *******************************************************************/
+
+typedef size_t (*zck_wcb)(void *ptr, size_t l, size_t c, void *dl_v);
+typedef struct zckDLPriv zckDLPriv;
+
+/* Contains a zchunk download context */
+typedef struct zckDL {
+    size_t dl;
+    size_t ul;
+    zck_wcb write_cb;
+    void *wdata;
+    zck_wcb header_cb;
+    void *hdrdata;
+    zckRange *range;
+    zckDLPriv *priv;
+    struct zckCtx *zck;
+} zckDL;
+
+/*******************************************************************
+ * Ranges
+ *******************************************************************/
+/* Get any matching chunks from src and put them in the right place in tgt */
+int zck_copy_chunks(zckCtx *src, zckCtx *tgt)
+    __attribute__ ((warn_unused_result));
+/* Free zckRange */
+void zck_range_free(zckRange **info);
+/* Get range string from start and end location */
+char *zck_get_range(size_t start, size_t end)
+    __attribute__ ((warn_unused_result));
+/* Get the minimum size needed to download in order to know how large the header
+ * is */
+int zck_get_min_download_size()
+    __attribute__ ((warn_unused_result));
+
+/*******************************************************************
+ * Downloading
+ *******************************************************************/
+/* Initialize zchunk download context */
+zckDL *zck_dl_init(zckCtx *zck)
+    __attribute__ ((warn_unused_result));
+/* Reset zchunk download context for reuse */
+void zck_dl_reset(zckDL *dl);
+/* Free zchunk download context */
+void zck_dl_free(zckDL **dl);
+/* Write callback.  You *must* pass this and your initialized zchunk download
+ * context to the downloader when downloading a zchunk file.  If you have your
+ * own callback, set dl->write_cb to your callback and dl->wdata to your
+ * callback data. */
+size_t zck_write_chunk_cb(void *ptr, size_t l, size_t c, void *dl_v);
+size_t zck_write_zck_header_cb(void *ptr, size_t l, size_t c, void *dl_v);
+size_t zck_header_cb(char *b, size_t l, size_t c, void *dl_v);
+/* Clear regex used for extracting download ranges from multipart download */
+void zck_dl_clear_regex(zckDL *dl);
+/* Download and process the header from url */
+int zck_dl_get_header(zckCtx *zck, zckDL *dl, char *url)
+    __attribute__ ((warn_unused_result));
+/* Get number of bytes downloaded using download context */
+size_t zck_dl_get_bytes_downloaded(zckDL *dl)
+    __attribute__ ((warn_unused_result));
+/* Get number of bytes uploaded using download context */
+size_t zck_dl_get_bytes_uploaded(zckDL *dl)
+    __attribute__ ((warn_unused_result));
+
+#endif
index c49ad0f88f2d0ef0badc33d34b1526c0a096d953..58c81074c06a3c2d645cad1a7b200008278fbd85 100644 (file)
@@ -5,3 +5,9 @@ empty = executable('empty', ['empty.c'] + util_sources, include_directories: inc
 file_path = join_paths(meson.source_root(), 'test/files')
 
 test('create and validate empty zchunk file', empty)
+
+run_target('test-abi',
+           command: 'abi.sh')
+
+run_target('new-abi',
+           command: 'new_abi.sh')
diff --git a/test/new_abi.sh b/test/new_abi.sh
new file mode 100755 (executable)
index 0000000..1d848e5
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+cd "$(dirname "$0")"
+
+if [ ! -e ../build/src/lib/libzck.so.*.*.* ]; then
+    echo "No library exists"
+    exit 1
+fi
+
+# Remove stable build and copy current build abi/stable
+rm abi/stable -rf
+mkdir -p abi/stable
+cp -a ../build/src/lib/libzck.so.* abi/stable
+cp -a ../include/zck.h abi/stable
+find abi -type l -delete