diff --git a/dev-requirements.txt b/dev-requirements.txt
index 5b6a770..4cca607 100644
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -1,3 +1,4 @@
 pytest >= 7.2.0
 pylint >= 2.15.10
-black >= 22.12.0
\ No newline at end of file
+black >= 22.12.0
+python-libarchive >= 4.2.1
\ No newline at end of file
diff --git a/tests/test_data/integration_input/config b/tests/test_data/integration_input/config
new file mode 100644
index 0000000..16194e2
--- /dev/null
+++ b/tests/test_data/integration_input/config
@@ -0,0 +1,5 @@
+variables:
+{
+    UPDATE_VERSION = "1.0.0";
+    PRODUCT = "test device";
+}
\ No newline at end of file
diff --git a/tests/test_data/integration_input/enc-sw-description.in b/tests/test_data/integration_input/enc-sw-description.in
new file mode 100644
index 0000000..1194f32
--- /dev/null
+++ b/tests/test_data/integration_input/enc-sw-description.in
@@ -0,0 +1,95 @@
+software =
+{
+        version = "@@UPDATE_VERSION@@";
+        description = "Firmware update for @@PRODUCT@@";
+
+        hardware-compatibility: [ "1.0", "1.2", "1.3"];
+
+        /* partitions tag is used to resize UBI partitions */
+        partitions: ( /* UBI Volumes */
+                {
+                        name = "rootfs";
+                        device = "mtd4";
+                        size = 104896512; /* in bytes */
+                },
+                {
+                        name = "data";
+                        device = "mtd5";
+                        size = 50448384; /* in bytes */
+                }
+        );
+
+
+        images: (
+                {
+                        filename = "rootfs.ubifs";
+                        volume = "rootfs";
+                        encrypted = true;
+                },
+                {
+                        filename = "swupdate.ext3.gz.u-boot";
+                        volume = "fs_recovery";
+                        encrypted = true;
+                },
+                {
+                        filename = "sdcard.ext3.gz";
+                        device = "/dev/mmcblk0p1";
+                        compressed = "zlib";
+                        encrypted = true;
+                },
+                {
+                        filename = "bootlogo.bmp";
+                        volume = "splash";
+                        encrypted = true;
+                },
+                {
+                        filename = "uImage.bin";
+                        volume = "kernel";
+                        encrypted = true;
+                },
+                {
+                        filename = "fpga.txt";
+                        type = "fpga";
+                        encrypted = true;
+                },
+                {
+                        filename = "bootloader-env";
+                        type = "bootloader";
+                        encrypted = true;
+                }
+        );
+
+        files: (
+                {
+                        filename = "README";
+                        path = "/README";
+                        device = "/dev/mmcblk0p1";
+                        filesystem = "vfat";
+                        encrypted = true;
+                }
+        );
+
+        scripts: (
+                {
+                        filename = "erase_at_end";
+                        type = "lua";
+                        encrypted = true;
+                },
+                {
+                        filename = "display_info";
+                        type = "lua";
+                        encrypted = true;
+                }
+        );
+
+        bootenv: (
+                {
+                        name = "vram";
+                        value = "4M";
+                },
+                {
+                        name = "addfb";
+                        value = "setenv bootargs ${bootargs} omapfb.vram=1:2M,2:2M,3:2M omapdss.def_disp=lcd"
+                }
+        );
+}
\ No newline at end of file
diff --git a/tests/test_data/integration_input/private.pem b/tests/test_data/integration_input/private.pem
new file mode 100644
index 0000000..94f474b
--- /dev/null
+++ b/tests/test_data/integration_input/private.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEogIBAAKCAQEA8e++KmilZGCc+906v/nQwbwipjiHHqfU6z/Zrr1Dbin2P4w6
+Pe2oabKa/2Ov2tKKylISBtXOyi4aVOiWyl2ZPhAj3B4EhqehwRb/2GwmqwsrL4Xq
+iJlNIVTfoMBi1ULy4hMWeVmdc3Z88/bf1WI2kfAK9nBqiDHWBILTNA+YtVv1XomP
+mYQi6W8FN8mdYMWgQy+C/T1p6WuDm9mlHQOHlzesoWIO6lkXTe7bsSb1DU4u886P
+CVoBCe0w2LnuzCTISiUXpgHKdlS9SrAfVvCdrGPBxlrt6DFe6QBsvSVZXd7EanLZ
+X75Um42wSHAWsAHPZlzVtRweBBKkF7fkIe4fvwIDAQABAoIBABkLOCQrsPMzDQ0F
+WY+FzJZBY1TRhSsnNGMluOLdtJ0yusrZOS4v678FPgYxy4JbSQKofDU47K8BFriz
+WuiXx8Uk5pFiihVmRNg4CUPd7iLGhTHmKuD4/YL1xjBdud1ZkMrWLv1gyWuqWETo
+yULNZ9izgG8CNATlI8JTyIkbFDOxnanQJwwEk+BRNqAwEgT8DMVgSyCmhjUVis81
+mDXxXDqGN/xSkRudfFuAgv3bx3aojV8v6+ehdA8w0eeKPhgJjDJYcLUh8yNZheO+
+MGd0WIkOBwZmt9m0knxkzil/Z75ZsRPc8wTw7PDSu0w8swc8EVdFHpJYbfxSyIdm
+IrQrzAECgYEA/61Pt6XgShHawta1k/Lr5Z6Bh4lXOX94RS2xFgIz7e2HqQd6QPUX
+h4vJnZ2W837XcFGsuajfF+roCAo8rZFGup3kpcIRnxc/hWRAsoB+/40u/IFwgHEQ
+FuUaxqK47VbCtkdEILQIBkMHNSEYO2Ko/n6nmoOXZkzDDK0CFqfP8bsCgYEA8j38
+1Hk9NaN2aZJVw83sYTshSLM7qoq23trSiwv1jliwheue2Epw9XT7CQF+5ktxwyvl
+CZ7Eu9BYcFcWZpPwAcCa5U1/jjC343maIvbeTBtV+aFg1UxlpsVu6S+lu8+CHVL0
+f9g+FYZsqkl03ZGbguRx/e48QJfiuqe9384ZV80CgYAkcxG9TbGG/bqhMjjaqbQF
+nS48I1FDCjAcNKJdT90VW1qOt1kvb4F2OnB4vuGpPvj5szsbkL6VS1De7I6v89kQ
+e7gABYW7l3Xfz2YFzJnOVtNO/ikKtpOjn+/MR6BzfX3uvIQy4VePhPi/E0PAG5Wa
+CnZcacwosmLQKM32auATRwKBgGUJk9Xvh6dCudYI0jrsPgbECfrvvxg/6UyEisKy
+R0aLGX2SLFvcmMbYdwhnlk1p9FZKjap4jWgk225n9JDubXHdqv2vWF+vVFPN2Ytx
+2oB1+mM3e1McHV31BXC/jeoLACNJAW/9es+xlMtl/heYbvumWyFl572tXEUsR9b8
+eLeVAoGAIYEHwYigSiuHBtCXLE4529w01x2sus00mzD7QOPBqTpGkTu5EGdcwyMJ
+7Y3en0uLC5MXnl5HhjBnmtHLYItxpEewxLprgjkPCdQM9/3NFAh3x0MFDvbXlnje
+hpkwhv8YXXqItzvOHRDZy4ZDQQSHEwrxvsQLmyLWmHdBC/6o/RQ=
+-----END RSA PRIVATE KEY-----
diff --git a/tests/test_data/integration_input/sw-description b/tests/test_data/integration_input/sw-description
new file mode 100644
index 0000000..2ac512d
--- /dev/null
+++ b/tests/test_data/integration_input/sw-description
@@ -0,0 +1,85 @@
+software =
+{
+        version = "1.0.0";
+        description = "Firmware update for XXXXX Project";
+
+        hardware-compatibility: [ "1.0", "1.2", "1.3"];
+
+        /* partitions tag is used to resize UBI partitions */
+        partitions: ( /* UBI Volumes */
+                {
+                        name = "rootfs";
+                        device = "mtd4";
+                        size = 104896512; /* in bytes */
+                },
+                {
+                        name = "data";
+                        device = "mtd5";
+                        size = 50448384; /* in bytes */
+                }
+        );
+
+
+        images: (
+                {
+                        filename = "rootfs.ubifs";
+                        volume = "rootfs";
+                },
+                {
+                        filename = "swupdate.ext3.gz.u-boot";
+                        volume = "fs_recovery";
+                },
+                {
+                        filename = "sdcard.ext3.gz";
+                        device = "/dev/mmcblk0p1";
+                        compressed = "zlib";
+                },
+                {
+                        filename = "bootlogo.bmp";
+                        volume = "splash";
+                },
+                {
+                        filename = "uImage.bin";
+                        volume = "kernel";
+                },
+                {
+                        filename = "fpga.txt";
+                        type = "fpga";
+                },
+                {
+                        filename = "bootloader-env";
+                        type = "bootloader";
+                }
+        );
+
+        files: (
+                {
+                        filename = "README";
+                        path = "/README";
+                        device = "/dev/mmcblk0p1";
+                        filesystem = "vfat"
+                }
+        );
+
+        scripts: (
+                {
+                        filename = "erase_at_end";
+                        type = "lua";
+                },
+                {
+                        filename = "display_info";
+                        type = "lua";
+                }
+        );
+
+        bootenv: (
+                {
+                        name = "vram";
+                        value = "4M";
+                },
+                {
+                        name = "addfb";
+                        value = "setenv bootargs ${bootargs} omapfb.vram=1:2M,2:2M,3:2M omapdss.def_disp=lcd"
+                }
+        );
+}
\ No newline at end of file
diff --git a/tests/test_data/integration_input/sw-description.in b/tests/test_data/integration_input/sw-description.in
new file mode 100644
index 0000000..bfe4ebc
--- /dev/null
+++ b/tests/test_data/integration_input/sw-description.in
@@ -0,0 +1,85 @@
+software =
+{
+        version = "@@UPDATE_VERSION@@";
+        description = "Firmware update for @@PRODUCT@@";
+
+        hardware-compatibility: [ "1.0", "1.2", "1.3"];
+
+        /* partitions tag is used to resize UBI partitions */
+        partitions: ( /* UBI Volumes */
+                {
+                        name = "rootfs";
+                        device = "mtd4";
+                        size = 104896512; /* in bytes */
+                },
+                {
+                        name = "data";
+                        device = "mtd5";
+                        size = 50448384; /* in bytes */
+                }
+        );
+
+
+        images: (
+                {
+                        filename = "rootfs.ubifs";
+                        volume = "rootfs";
+                },
+                {
+                        filename = "swupdate.ext3.gz.u-boot";
+                        volume = "fs_recovery";
+                },
+                {
+                        filename = "sdcard.ext3.gz";
+                        device = "/dev/mmcblk0p1";
+                        compressed = "zlib";
+                },
+                {
+                        filename = "bootlogo.bmp";
+                        volume = "splash";
+                },
+                {
+                        filename = "uImage.bin";
+                        volume = "kernel";
+                },
+                {
+                        filename = "fpga.txt";
+                        type = "fpga";
+                },
+                {
+                        filename = "bootloader-env";
+                        type = "bootloader";
+                }
+        );
+
+        files: (
+                {
+                        filename = "README";
+                        path = "/README";
+                        device = "/dev/mmcblk0p1";
+                        filesystem = "vfat"
+                }
+        );
+
+        scripts: (
+                {
+                        filename = "erase_at_end";
+                        type = "lua";
+                },
+                {
+                        filename = "display_info";
+                        type = "lua";
+                }
+        );
+
+        bootenv: (
+                {
+                        name = "vram";
+                        value = "4M";
+                },
+                {
+                        name = "addfb";
+                        value = "setenv bootargs ${bootargs} omapfb.vram=1:2M,2:2M,3:2M omapdss.def_disp=lcd"
+                }
+        );
+}
\ No newline at end of file
diff --git a/tests/test_data/integration_output/output.swu b/tests/test_data/integration_output/output.swu
new file mode 100644
index 0000000000000000000000000000000000000000..972a02bdef7258aa9f17e14746af73ca8d10f67e
GIT binary patch
diff --git a/tests/test_data/integration_output/output.swu.enc b/tests/test_data/integration_output/output.swu.enc
new file mode 100644
index 0000000000000000000000000000000000000000..05d810db106618ca5285f5f3ac3711d889653155
GIT binary patch
diff --git a/tests/test_data/integration_output/signed_output.swu b/tests/test_data/integration_output/signed_output.swu
new file mode 100644
index 0000000000000000000000000000000000000000..5f24655ee40a5efd615f20c7777892226f5e275e
GIT binary patch
diff --git a/tests/test_data/integration_output/signed_output.swu.enc b/tests/test_data/integration_output/signed_output.swu.enc
new file mode 100644
index 0000000000000000000000000000000000000000..29304b2f9d9137b4c3f57c061c504e054b05fdd6
GIT binary patch
diff --git a/tests/test_integration.py b/tests/test_integration.py
new file mode 100644
index 0000000..d48b615
--- /dev/null
+++ b/tests/test_integration.py
@@ -0,0 +1,201 @@
+# pylint: disable=C0114,C0116,W0621
+"""This file hosts integration tests to ensure tool creates valid SWUs"""
+from pathlib import Path
+import pytest
+import shutil
+
+import libarchive
+
+from swugenerator import main
+
+VALID_KEY = "390ad54490a4a5f53722291023c19e08ffb5c4677a59e958c96ffa6e641df040"
+VALID_IV = "d5d601bacfe13100b149177318ebc7a4"
+UPDATE_FILES = [
+    "rootfs.ubifs",
+    "swupdate.ext3.gz.u-boot",
+    "sdcard.ext3.gz",
+    "bootlogo.bmp",
+    "uImage.bin",
+    "fpga.txt",
+    "bootloader-env",
+    "README",
+    "erase_at_end",
+    "display_info",
+]
+
+
+@pytest.fixture()
+def input_directory(tmp_path_factory):
+    """Creates a directory to test"""
+    return tmp_path_factory.mktemp("input_files")
+
+
+@pytest.fixture()
+def output_directory(tmp_path_factory):
+    """Creates a directory to test"""
+    return tmp_path_factory.mktemp("output_files")
+
+
+@pytest.fixture()
+def artifactory(input_directory):
+    """Creates test files that match the filenames in the sw-description"""
+    for filename in UPDATE_FILES:
+        file = input_directory / filename
+        with file.open("w") as file_fd:
+            file_fd.write("THIS IS A TEST UPDATE FILE\n")
+    return input_directory.resolve()
+
+
+def copy_to_test_dir(filename, test_dir) -> Path:
+    """Helper function to copy integration test inputs to test directory"""
+    source_path = Path(__file__).parent / "test_data/integration_input" / filename
+    dest_path = test_dir / filename
+    shutil.copy(source_path, dest_path)
+    return dest_path.resolve()
+
+
+@pytest.fixture()
+def sw_description_template(input_directory):
+    """Copies sw-description template to test directory"""
+    filename = "sw-description.in"
+    return copy_to_test_dir(filename, input_directory)
+
+
+@pytest.fixture()
+def encrypted_sw_description_template(input_directory):
+    """Copies sw-description template to test directory"""
+    filename = "enc-sw-description.in"
+    return copy_to_test_dir(filename, input_directory)
+
+@pytest.fixture()
+def config_file(input_directory):
+    """Copies config file to test directory"""
+    filename = "config"
+    return copy_to_test_dir(filename, input_directory)
+
+
+@pytest.fixture()
+def signing_key(input_directory):
+    """Creates signing key"""
+    filename = "private.pem"
+    return copy_to_test_dir(filename, input_directory)
+
+
+@pytest.fixture()
+def encryption_key(input_directory):
+    """Creates encryption key"""
+    encryption_key_filename = "valid_key.txt"
+    encryption_key_path = input_directory / encryption_key_filename
+    with encryption_key_path.open("w") as key_key_fd:
+        key_key_fd.write(f"key={VALID_KEY}\niv={VALID_IV}")
+    return encryption_key_path
+
+
+def validate_swu(output_swu, encrypted=False):
+    """Helper function to validate the output file against a pre-generated output file"""
+    reference_swu = (
+        Path(__file__).parent / "test_data/integration_output" / output_swu.name
+    )
+    with libarchive.Archive(output_swu.open()) as output, libarchive.Archive(
+        reference_swu.open()
+    ) as reference:
+        for output_file, reference_file in zip(output, reference):
+            if output_file.pathname != reference_file.pathname:
+                print("Names do not match")
+                return False
+            if output_file.size != reference_file.size:
+                print("Sizes do not match")
+                return False
+            if not encrypted and output.read(output_file.size) != reference.read(output_file.size):
+                print("File contents are not equal")
+                return False
+    return True
+
+
+def test_basic_command_creates_valid_swu(
+    artifactory, sw_description_template, config_file, output_directory
+):
+    output_file = "output.swu"
+    command_args = [
+        "-s",
+        str(sw_description_template),
+        "-a",
+        str(artifactory),
+        "-c",
+        str(config_file),
+        "-o",
+        str((output_directory / output_file).resolve()),
+        "create",
+    ]
+    main.parse_args(command_args)
+    assert validate_swu(output_directory / output_file)
+
+
+def test_command_with_sign_flag_creates_valid_signed_swu(
+    artifactory, sw_description_template, config_file, signing_key, output_directory
+):
+    output_file = "signed_output.swu"
+    command_args = [
+        "-s",
+        str(sw_description_template),
+        "-a",
+        str(artifactory),
+        "-c",
+        str(config_file),
+        "-k",
+        f"RSA,{signing_key}",
+        "-o",
+        str((output_directory / output_file).resolve()),
+        "create",
+    ]
+    main.parse_args(command_args)
+    assert validate_swu(output_directory / output_file)
+
+
+def test_command_with_encryption_flag_creates_encrypted_swu(
+    artifactory, encrypted_sw_description_template, config_file, encryption_key, output_directory
+):
+    output_file = "output.swu.enc"
+    command_args = [
+        "-s",
+        str(encrypted_sw_description_template),
+        "-a",
+        str(artifactory),
+        "-c",
+        str(config_file),
+        "-K",
+        str(encryption_key),
+        "-o",
+        str((output_directory / output_file).resolve()),
+        "create",
+    ]
+    main.parse_args(command_args)
+    assert validate_swu(output_directory / output_file, encrypted=True)
+
+
+def test_command_with_sign_flag_and_encrypt_flag_creates_signed_encrypted_swu(
+    artifactory,
+    encrypted_sw_description_template,
+    config_file,
+    signing_key,
+    encryption_key,
+    output_directory,
+):
+    output_file = "signed_output.swu.enc"
+    command_args = [
+        "-s",
+        str(encrypted_sw_description_template),
+        "-a",
+        str(artifactory),
+        "-c",
+        str(config_file),
+        "-k",
+        f"RSA,{signing_key}",
+        "-K",
+        str(encryption_key),
+        "-o",
+        str((output_directory / output_file).resolve()),
+        "create",
+    ]
+    main.parse_args(command_args)
+    assert validate_swu(output_directory / output_file, encrypted=True)
