diff mbox series

[v4,6/6] tests/qtest: migration-test: Add tests for file-based migration

Message ID 20230706201927.15442-7-farosas@suse.de
State New
Headers show
Series migration: Test the new "file:" migration | expand

Commit Message

Fabiano Rosas July 6, 2023, 8:19 p.m. UTC
Add basic tests for file-based migration.

Signed-off-by: Fabiano Rosas <farosas@suse.de>
Reviewed-by: Peter Xu <peterx@redhat.com>
---
 tests/qtest/migration-test.c | 99 ++++++++++++++++++++++++++++++++++++
 1 file changed, 99 insertions(+)

Comments

Fabiano Rosas July 11, 2023, 10:27 p.m. UTC | #1
Fabiano Rosas <farosas@suse.de> writes:

> Add basic tests for file-based migration.
>
> Signed-off-by: Fabiano Rosas <farosas@suse.de>
> Reviewed-by: Peter Xu <peterx@redhat.com>
> ---
>  tests/qtest/migration-test.c | 99 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 99 insertions(+)
>
> diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
> index 2fdf6a115e..c052dbe1f1 100644
> --- a/tests/qtest/migration-test.c
> +++ b/tests/qtest/migration-test.c
> @@ -52,6 +52,10 @@ static bool got_dst_resume;
>   */
>  #define DIRTYLIMIT_TOLERANCE_RANGE  25  /* MB/s */
>  
> +#define QEMU_VM_FILE_MAGIC 0x5145564d
> +#define FILE_TEST_FILENAME "migfile"
> +#define FILE_TEST_OFFSET 0x1000
> +
>  #if defined(__linux__)
>  #include <sys/syscall.h>
>  #include <sys/vfs.h>
> @@ -762,6 +766,7 @@ static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest)
>      cleanup("migsocket");
>      cleanup("src_serial");
>      cleanup("dest_serial");
> +    cleanup(FILE_TEST_FILENAME);
>  }
>  
>  #ifdef CONFIG_GNUTLS
> @@ -1459,11 +1464,28 @@ static void test_precopy_common(MigrateCommon *args)
>               */
>              wait_for_migration_complete(from);
>  
> +            /*
> +             * For file based migration the target must begin its
> +             * migration after the source has finished.
> +             */
> +            if (strstr(connect_uri, "file:")) {
> +                migrate_incoming_qmp(to, connect_uri, "{}");
> +            }
> +

This is now broken since we merged commit e02f56e3de ("tests/qtest:
massively speed up migration-test").

We cannot monitor the destination while the source is still running
because we need the source to have finished writing to the file before
we can start the destination. I'll have to think of another way of
testing a migration that is done with a live source but asynchronous
incoming migration.

Any suggestions are welcome.
Daniel P. Berrangé July 12, 2023, 7:03 a.m. UTC | #2
On Tue, Jul 11, 2023 at 07:27:42PM -0300, Fabiano Rosas wrote:
> Fabiano Rosas <farosas@suse.de> writes:
> 
> > Add basic tests for file-based migration.
> >
> > Signed-off-by: Fabiano Rosas <farosas@suse.de>
> > Reviewed-by: Peter Xu <peterx@redhat.com>
> > ---
> >  tests/qtest/migration-test.c | 99 ++++++++++++++++++++++++++++++++++++
> >  1 file changed, 99 insertions(+)
> >
> > diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
> > index 2fdf6a115e..c052dbe1f1 100644
> > --- a/tests/qtest/migration-test.c
> > +++ b/tests/qtest/migration-test.c
> > @@ -52,6 +52,10 @@ static bool got_dst_resume;
> >   */
> >  #define DIRTYLIMIT_TOLERANCE_RANGE  25  /* MB/s */
> >  
> > +#define QEMU_VM_FILE_MAGIC 0x5145564d
> > +#define FILE_TEST_FILENAME "migfile"
> > +#define FILE_TEST_OFFSET 0x1000
> > +
> >  #if defined(__linux__)
> >  #include <sys/syscall.h>
> >  #include <sys/vfs.h>
> > @@ -762,6 +766,7 @@ static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest)
> >      cleanup("migsocket");
> >      cleanup("src_serial");
> >      cleanup("dest_serial");
> > +    cleanup(FILE_TEST_FILENAME);
> >  }
> >  
> >  #ifdef CONFIG_GNUTLS
> > @@ -1459,11 +1464,28 @@ static void test_precopy_common(MigrateCommon *args)
> >               */
> >              wait_for_migration_complete(from);
> >  
> > +            /*
> > +             * For file based migration the target must begin its
> > +             * migration after the source has finished.
> > +             */
> > +            if (strstr(connect_uri, "file:")) {
> > +                migrate_incoming_qmp(to, connect_uri, "{}");
> > +            }
> > +
> 
> This is now broken since we merged commit e02f56e3de ("tests/qtest:
> massively speed up migration-test").
> 
> We cannot monitor the destination while the source is still running
> because we need the source to have finished writing to the file before
> we can start the destination. I'll have to think of another way of
> testing a migration that is done with a live source but asynchronous
> incoming migration.
> 
> Any suggestions are welcome.

Don't use test_precopy_common() at all. This helper is written from the
POV that we're actually doing a live migration. Migrate to/from file is
not live migration.

So open code the subset of pieces of test_precopy_common() that you
need for file migration. There are a handful of other tests that
take this approach since test_precopy_common wasn't suitable for
them eg test_migrate_auto_converge()

With regards,
Daniel
diff mbox series

Patch

diff --git a/tests/qtest/migration-test.c b/tests/qtest/migration-test.c
index 2fdf6a115e..c052dbe1f1 100644
--- a/tests/qtest/migration-test.c
+++ b/tests/qtest/migration-test.c
@@ -52,6 +52,10 @@  static bool got_dst_resume;
  */
 #define DIRTYLIMIT_TOLERANCE_RANGE  25  /* MB/s */
 
+#define QEMU_VM_FILE_MAGIC 0x5145564d
+#define FILE_TEST_FILENAME "migfile"
+#define FILE_TEST_OFFSET 0x1000
+
 #if defined(__linux__)
 #include <sys/syscall.h>
 #include <sys/vfs.h>
@@ -762,6 +766,7 @@  static void test_migrate_end(QTestState *from, QTestState *to, bool test_dest)
     cleanup("migsocket");
     cleanup("src_serial");
     cleanup("dest_serial");
+    cleanup(FILE_TEST_FILENAME);
 }
 
 #ifdef CONFIG_GNUTLS
@@ -1459,11 +1464,28 @@  static void test_precopy_common(MigrateCommon *args)
              */
             wait_for_migration_complete(from);
 
+            /*
+             * For file based migration the target must begin its
+             * migration after the source has finished.
+             */
+            if (strstr(connect_uri, "file:")) {
+                migrate_incoming_qmp(to, connect_uri, "{}");
+            }
+
             if (!got_src_stop) {
                 qtest_qmp_eventwait(from, "STOP");
             }
         } else {
             wait_for_migration_complete(from);
+
+            /*
+             * For file based migration the target must begin its
+             * migration after the source has finished.
+             */
+            if (strstr(connect_uri, "file:")) {
+                migrate_incoming_qmp(to, connect_uri, "{}");
+            }
+
             /*
              * Must wait for dst to finish reading all incoming
              * data on the socket before issuing 'cont' otherwise
@@ -1681,6 +1703,75 @@  static void test_precopy_unix_compress_nowait(void)
     test_precopy_common(&args);
 }
 
+static void test_precopy_file(void)
+{
+    g_autofree char *uri = g_strdup_printf("file:%s/%s", tmpfs,
+                                           FILE_TEST_FILENAME);
+    MigrateCommon args = {
+        .connect_uri = uri,
+        .listen_uri = "defer",
+    };
+
+    test_precopy_common(&args);
+}
+
+static void file_offset_finish_hook(QTestState *from, QTestState *to, void *opaque)
+{
+#if defined(__linux__)
+    g_autofree char *path = g_strdup_printf("%s/%s", tmpfs, FILE_TEST_FILENAME);
+    size_t size = FILE_TEST_OFFSET + sizeof(QEMU_VM_FILE_MAGIC);
+    uintptr_t *addr, *p;
+    int fd;
+
+    fd = open(path, O_RDONLY);
+    g_assert(fd != -1);
+    addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+    g_assert(addr != MAP_FAILED);
+
+    /*
+     * Ensure the skipped offset contains zeros and the migration
+     * stream starts at the right place.
+     */
+    p = addr;
+    while (p < addr + FILE_TEST_OFFSET / sizeof(uintptr_t)) {
+        g_assert(*p == 0);
+        p++;
+    }
+    g_assert_cmpint(cpu_to_be32(*p), ==, QEMU_VM_FILE_MAGIC);
+
+    munmap(addr, size);
+    close(fd);
+#endif
+}
+
+static void test_precopy_file_offset(void)
+{
+    g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=%d", tmpfs,
+                                           FILE_TEST_FILENAME,
+                                           FILE_TEST_OFFSET);
+    MigrateCommon args = {
+        .connect_uri = uri,
+        .listen_uri = "defer",
+        .finish_hook = file_offset_finish_hook,
+    };
+
+    test_precopy_common(&args);
+}
+
+static void test_precopy_file_offset_bad(void)
+{
+    /* using a value not supported by qemu_strtosz() */
+    g_autofree char *uri = g_strdup_printf("file:%s/%s,offset=0x20M",
+                                           tmpfs, FILE_TEST_FILENAME);
+    MigrateCommon args = {
+        .connect_uri = uri,
+        .listen_uri = "defer",
+        .result = MIG_TEST_QMP_ERROR,
+    };
+
+    test_precopy_common(&args);
+}
+
 static void test_precopy_tcp_plain(void)
 {
     MigrateCommon args = {
@@ -2730,6 +2821,14 @@  int main(int argc, char **argv)
         qtest_add_func("/migration/precopy/unix/compress/nowait",
                        test_precopy_unix_compress_nowait);
     }
+
+    qtest_add_func("/migration/precopy/file",
+                   test_precopy_file);
+    qtest_add_func("/migration/precopy/file/offset",
+                   test_precopy_file_offset);
+    qtest_add_func("/migration/precopy/file/offset/bad",
+                   test_precopy_file_offset_bad);
+
 #ifdef CONFIG_GNUTLS
     qtest_add_func("/migration/precopy/unix/tls/psk",
                    test_precopy_unix_tls_psk);