diff mbox series

[swugenerator,3/3] Add integration tests

Message ID 20230127202639.505959-4-colin.mcallister@garmin.com
State Accepted
Headers show
Series Refactor main and add initial tests | expand

Commit Message

Colin McAllister Jan. 27, 2023, 8:26 p.m. UTC
From: Colin McAllister <colinmca242@gmail.com>

In order to ensure the swugenerator tool works as expected for basic use
cases, integration tests have been created. These can be expanded if
desired, but coverage could be expanded by adding tests for generator.

Signed-off-by: Colin McAllister <colinmca242@gmail.com>
---
 dev-requirements.txt                          |   3 +-
 tests/test_data/integration_input/config      |   5 +
 .../integration_input/enc-sw-description.in   |  95 +++++++++
 tests/test_data/integration_input/private.pem |  27 +++
 .../integration_input/sw-description          |  85 ++++++++
 .../integration_input/sw-description.in       |  85 ++++++++
 tests/test_data/integration_output/output.swu | Bin 0 -> 4608 bytes
 .../integration_output/output.swu.enc         | Bin 0 -> 5632 bytes
 .../integration_output/signed_output.swu      | Bin 0 -> 5120 bytes
 .../integration_output/signed_output.swu.enc  | Bin 0 -> 6144 bytes
 tests/test_integration.py                     | 201 ++++++++++++++++++
 11 files changed, 500 insertions(+), 1 deletion(-)
 create mode 100644 tests/test_data/integration_input/config
 create mode 100644 tests/test_data/integration_input/enc-sw-description.in
 create mode 100644 tests/test_data/integration_input/private.pem
 create mode 100644 tests/test_data/integration_input/sw-description
 create mode 100644 tests/test_data/integration_input/sw-description.in
 create mode 100644 tests/test_data/integration_output/output.swu
 create mode 100644 tests/test_data/integration_output/output.swu.enc
 create mode 100644 tests/test_data/integration_output/signed_output.swu
 create mode 100644 tests/test_data/integration_output/signed_output.swu.enc
 create mode 100644 tests/test_integration.py
diff mbox series

Patch

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
literal 4608
zcmd5=OK;;g5H?yYP^3NN)<X}g7(KMWMxox)E^<)TP8(o@7FoA@C<=oTNk>@85=7Zq
zXOZKc_J{PR^x9jm{R!>8hjK_iWNlK*K;48eB#OhwH#6UmLn9A)$V8}zP}p~oD83Qe
z@ODD9_7+VBv@c8OigBVC$eOpQ@A*gVbt>wnck;Z)uMP?2ahViVl8-y0@SIgwxTM<g
z-rGG*lqoH_kZH$S*U*uUy3b^DZ5W77lQNUTCI!J2)mUC?73Gyi=roDxe9$E>3G_OQ
z^Q^#C5+!L;&BRi$&`<ISHCU+or2c8He_CBB{8>RMa9JgQpU-FdYB^M?0CPea<4owK
zb;~@j7@uQOB5e*7#92k`hL9)MFw#J_AGnTTs)b?b%?ju3iwSe!#%#(a^QD}IaK4m-
zY}>bdyS9?l>TA`IWOzh3>C2LouIsE%qT~b3r+GU07sK#NY&tHWjeX)_i?BF09mh2s
z5;N)uelpkftSCTn6j>4R1OqK>2R>l|jSTG3z^9fMP_w4#oo1_J=2wbMI(<`F`siAp
z97e)*wQ0ZuEBK5LOB&~bv9m^>d(?r%g7ixbuG1uHU|X@_NK}uqERNFGs4yDcAY@9)
zIVIqVTjp8m=!kv8wS5}dzKbY{<G?VOLn(1h+wzEw9BO;9;TjQhBg3?8m)Y1LjIzjL
zLRee5m7l;VX+FyJC@X4X*PX+Q6!Xi5c!l}@=GNp4B1n&taRbtdPOoV>rfEZbe~4Kz
z!g}?lN&jkA$W0Bz4+g7Z1SYgRq~mD=)&lXWQ=`LfY+T<yVVBuv_q^zbz4LwprZ~Ya
zAr_Brm9`9PiDbqrn!!|4hMWG~y)o4Jzl}L)i8&qOYDmYVVU&e))5*hOBS~QMnGKUM
z%kLR(orJ)D5gjd)mT8Hz2KXsXCo=Z!^P1$&Eqjp)U_w~)5L!;fsl)`>a5>`Imv0x<
z8!gXp!6F@y92-x~^Cu=eEb)*c!nsZ;8-lry)40xzn}yyt&-OYUk>Sc5HwaPB3L!6T
zo#P_oMCP%Zb6k-?i{kc8mF=m_r_&jHd-hTjzfc?WUk<b%zVC&DzIJ-{qQAF>%a*zG
ze~-)X7r5@oZbS~=2BW+mI51axjHa^5M%x+ko`Ft!r~Je0Mc{k<{u8(=bUym{)4%@w
z?8i>`n|J%a|FQq>x6bFk?!S8EefRj4-udP47bjoHZfkaRg6%MG?{9UisBEO2ErExQ
z<W+lHw#KFSDtNfcIKV1xd@ON2-;uqfA0R#!dBql(B#(ArE4Y`+m{mSp<PTfftG^?A
ziEE9*rcV29Fv)BD7IE5|TgyGJejvB^qbvVE*nuCHxaucwJ6zJr8y@R_du-@j7pqtl
TErW|t?D!W42M6HChgALnY%KwO

literal 0
HcmV?d00001

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
literal 5632
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

literal 0
HcmV?d00001

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
literal 5120
zcmeHLZEO@p7(OvXXcfy3s75WzNeC3Wo&CJKV$rL;LK7$iiX<4)%<j%!*WTWpyL(5k
zO*LSM31H-h@PkN93<*(0qkn{m$cF^Q2x>%3AYv5_34sVCN`i_rv%R~$1?=|62|t`P
zd%N?_$Me3=J2TG|L_h@a0JH-TPY3{)C>IyWuM`IrzqpDc^`#P*aX(x*K>Oi0_nTH$
zJUWOi()M(_y{1V+wrUw!$H=5ZxY!xpSpzM^wAKvPFu3HAWn&xD%7i%<upm5-R(rY;
zQ-@)hv|BE#K?gB<#$p^~JB)_%hKfcy^+HP{t(w$~nT3v_7%9Uk;Hk(&&(bG(BNK(^
zdO!KfPa#Z=t6eBrXgLPKZ;y;LtJKwXfs9E?8k*QICTwLgj&6@&a!t$#P+~S6P4pRU
zV}SJJfEbO*634p}ldeN$oVT6~hXeXXb7L|xmE<#yOeFzPj0#cFGZXb{wp(GCFo{O<
zS2t3q(q}fO7&m#I&!lqy5*WJ|@{&x@s!=Th1x;5~UXo-^(o`KuI6rk+jtEK&sEQ&e
zS_EgH0L55T(_={CU<AdYNQlG`@A34uVe?|P*SOilqJBqUlLKt7Nx{^4h9L};;p=vf
zh13kr*n+Rk9rQs{anhGO7)Tk44_i4Kn(=G1X{t)94`exCGqPkXWZOt1RNP{mvX7Ds
zfGkFlB1UC^G*yjpoGu}x$-F2;G!aNhjHsN<DY~q1ydcWD2suqhx+3V<=$SbXPlS|I
zCYfOsGwbPFNsgUOLA%#yE@S?$b1T<LRuHQgX&<C=I`ttdjZ!}IokOf=laO`#{ps%%
zvUF1;=DP-~n-Ne$Ruf9+eXxp%%Z+>usuN@H_DOb`vFx7967lxM2_H;+g7uQM*nCTC
zz-3L56l@2XWT?Cj{rpxx81DH$mT({o+NcLQJt(dDf>I<mmAiYgQ8UQqQ|K|$dgczp
z^(G<7f4n*Zik7?uO&|C?Oy%g>7Z-ahx81UfQUGe2?mvV|L)nO8BG{mnw3!)$#n&Mw
zW5TSiumnjf*TOHJ%aezIAJnATHmf1MhlIN|rFt`CsOb05yqZu5E8McirJ6Rd#w{w|
zQ8g~-YG*zsRBBw-Hj+f=&U>f@?m545!!JuGyt_Ge;#&RWsVARkc~ffq;-}_wN1i-C
ztLxK!!^dC9*UdP3ZR3KOZxvSmaDB(BmZ^n3+YU^;(DnTA?rjs*SDDZQsXq!U8XBeE
zO<?f-f!?Pk^=$d;=ShVFAH8QvH&*RF%dH*k+&=u`@o$vJj$G;A@a;>RX4k$mY5&&i
zZ@|`LS9cx$@X=TF{_x@Pm(~vN>NCd;*T4OB?eY1wugTw^9N2nV@1HznW=n4KoWGa!
zElghA_c?p;!L^4D9&1=9bj)u^e%XM!YA)@4c;}T5?zypj|IXjfq(8ZO@a6k<TyEH~
z<;<y#=a#3pe|-4$v!A7ZJ^lFZi}K!eQ=U82c;do$^>d0G#Nwb`7#jzGYooV`Q8^%&
z7+mB8?<#IreTG8a3p<xH_%F_MCzf|JE0(s$yAw=D=b}VSDK{uCiF6N~8-a0gQ8F&U
zbsL3=^CJjGdPk#otl$`VHzuRTj-#A_w)PJDW(A4yP1`tuq;Y86y|tHryZ@O`c)|L*
zQ$N<N|0+~}v~K12$dYL*+0f2E7qvY?n^nYBtUBNB(e5h3V6h~8i&(c-gKyyGE9Seb
z`bboQa7=OGD@|2!#mKlM4~yDv447!&;CUB#&658OP)sg|MGZHmc*V&ORlr7hAn|e)
z*H|#ot)v>5N_(7F6b0u|q9<AvVpYQBRX@RS5%xwa#e;aXb~oAGwTP>`m&Ngpzij&S
M>4eAsiyMJ|0HBSaS^xk5

literal 0
HcmV?d00001

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
literal 6144
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

literal 0
HcmV?d00001

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)