torture/spoolss: issue GetJob after StartDocPrinter
[obnox/samba/samba-obnox.git] / source4 / torture / rpc / spoolss.c
index 135eb3cb76030643a7c53b9456036a7089f5f74f..23f501d7401802021f4f663ef1567a04ccde1cd1 100644 (file)
@@ -77,8 +77,8 @@ struct test_spoolss_context {
        union spoolss_PortInfo *ports[3];
 
        /* for EnumPrinterDrivers */
-       uint32_t driver_count[8];
-       union spoolss_DriverInfo *drivers[8];
+       uint32_t driver_count[9];
+       union spoolss_DriverInfo *drivers[9];
 
        /* for EnumMonitors */
        uint32_t monitor_count[3];
@@ -513,30 +513,36 @@ static bool test_GetPrinterDriverDirectory(struct torture_context *tctx,
        return true;
 }
 
-static bool test_EnumPrinterDrivers_args(struct torture_context *tctx,
-                                        struct dcerpc_binding_handle *b,
-                                        const char *server_name,
-                                        const char *environment,
-                                        uint32_t level,
-                                        uint32_t *count_p,
-                                        union spoolss_DriverInfo **info_p)
+static bool test_EnumPrinterDrivers_buffers(struct torture_context *tctx,
+                                           struct dcerpc_binding_handle *b,
+                                           const char *server_name,
+                                           const char *environment,
+                                           uint32_t level,
+                                           uint32_t offered,
+                                           uint32_t *count_p,
+                                           union spoolss_DriverInfo **info_p)
 {
        struct spoolss_EnumPrinterDrivers r;
        uint32_t needed;
        uint32_t count;
        union spoolss_DriverInfo *info;
+       DATA_BLOB buffer;
+
+       if (offered > 0) {
+               buffer = data_blob_talloc_zero(tctx, offered);
+       }
 
        r.in.server             = server_name;
        r.in.environment        = environment;
        r.in.level              = level;
-       r.in.buffer             = NULL;
-       r.in.offered            = 0;
+       r.in.buffer             = offered ? &buffer : NULL;
+       r.in.offered            = offered;
        r.out.needed            = &needed;
        r.out.count             = &count;
        r.out.info              = &info;
 
-       torture_comment(tctx, "Testing EnumPrinterDrivers(%s) level %u\n",
-               r.in.environment, r.in.level);
+       torture_comment(tctx, "Testing EnumPrinterDrivers(%s) level %u, offered: %u\n",
+               r.in.environment, r.in.level, r.in.offered);
 
        torture_assert_ntstatus_ok(tctx,
                dcerpc_spoolss_EnumPrinterDrivers_r(b, tctx, &r),
@@ -567,6 +573,20 @@ static bool test_EnumPrinterDrivers_args(struct torture_context *tctx,
 
 }
 
+
+static bool test_EnumPrinterDrivers_args(struct torture_context *tctx,
+                                        struct dcerpc_binding_handle *b,
+                                        const char *server_name,
+                                        const char *environment,
+                                        uint32_t level,
+                                        uint32_t *count_p,
+                                        union spoolss_DriverInfo **info_p)
+{
+       return test_EnumPrinterDrivers_buffers(tctx, b, server_name,
+                                              environment, level, 0,
+                                              count_p, info_p);
+}
+
 static bool test_EnumPrinterDrivers_findone(struct torture_context *tctx,
                                            struct dcerpc_binding_handle *b,
                                            const char *server_name,
@@ -642,6 +662,7 @@ static bool test_EnumPrinterDrivers(struct torture_context *tctx,
        struct dcerpc_pipe *p = ctx->spoolss_pipe;
        struct dcerpc_binding_handle *b = p->binding_handle;
        uint16_t levels[] = { 1, 2, 3, 4, 5, 6, 8 };
+       uint16_t buffer_sizes[] = { 0, 1024, 6040, 0xffff };
        int i, j, a;
 
        /* FIXME: gd, come back and fix "" as server, and handle
@@ -655,6 +676,15 @@ static bool test_EnumPrinterDrivers(struct torture_context *tctx,
 
        for (a=0;a<ARRAY_SIZE(environments);a++) {
 
+       for (i=0;i<ARRAY_SIZE(buffer_sizes);i++) {
+               torture_assert(tctx,
+                       test_EnumPrinterDrivers_buffers(tctx, b, server_name,
+                                                       environments[a], 3,
+                                                       buffer_sizes[i],
+                                                       NULL, NULL),
+                       "failed to enumerate drivers");
+       }
+
        for (i=0;i<ARRAY_SIZE(levels);i++) {
                int level = levels[i];
                uint32_t count;
@@ -1874,13 +1904,14 @@ static bool test_sd_set_level(struct torture_context *tctx,
        struct spoolss_DevmodeContainer devmode_ctr;
        struct sec_desc_buf secdesc_ctr;
        union spoolss_SetPrinterInfo sinfo;
+       union spoolss_PrinterInfo info;
+       struct spoolss_SetPrinterInfo3 info3;
 
        ZERO_STRUCT(devmode_ctr);
        ZERO_STRUCT(secdesc_ctr);
 
        switch (level) {
        case 2: {
-               union spoolss_PrinterInfo info;
                torture_assert(tctx, test_GetPrinter_level(tctx, b, handle, 2, &info), "");
                torture_assert(tctx, PrinterInfo_to_SetPrinterInfo(tctx, &info, 2, &sinfo), "");
 
@@ -1890,7 +1921,6 @@ static bool test_sd_set_level(struct torture_context *tctx,
                break;
        }
        case 3: {
-               struct spoolss_SetPrinterInfo3 info3;
 
                info3.sec_desc_ptr = NULL;
 
@@ -3225,6 +3255,7 @@ static bool test_EnumJobs_args(struct torture_context *tctx,
                               struct dcerpc_binding_handle *b,
                               struct policy_handle *handle,
                               uint32_t level,
+                              WERROR werr_expected,
                               uint32_t *count_p,
                               union spoolss_JobInfo **info_p)
 {
@@ -3258,13 +3289,15 @@ static bool test_EnumJobs_args(struct torture_context *tctx,
                status = dcerpc_spoolss_EnumJobs_r(b, tctx, &r);
 
                torture_assert_ntstatus_ok(tctx, status, "EnumJobs failed");
-               torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
+               torture_assert_werr_equal(tctx, r.out.result, werr_expected,
+                                         "EnumJobs failed");
                torture_assert(tctx, info, "No jobs returned");
 
                CHECK_NEEDED_SIZE_ENUM_LEVEL(spoolss_EnumJobs, *r.out.info, r.in.level, count, needed, 4);
 
        } else {
-               torture_assert_werr_ok(tctx, r.out.result, "EnumJobs failed");
+               torture_assert_werr_equal(tctx, r.out.result, werr_expected,
+                                         "EnumJobs failed");
        }
 
        if (count_p) {
@@ -3413,6 +3446,9 @@ static bool test_DoPrintTest_add_one_job_common(struct torture_context *tctx,
        torture_assert_werr_ok(tctx, s.out.result, "StartDocPrinter failed");
 
        for (i=1; i < 4; i++) {
+               union spoolss_JobInfo ginfo;
+               bool ok;
+
                torture_comment(tctx, "Testing StartPagePrinter: Page[%d], JobId[%d]\n", i, *job_id);
 
                sp.in.handle            = handle;
@@ -3422,6 +3458,11 @@ static bool test_DoPrintTest_add_one_job_common(struct torture_context *tctx,
                                           "dcerpc_spoolss_StartPagePrinter failed");
                torture_assert_werr_ok(tctx, sp.out.result, "StartPagePrinter failed");
 
+               ok = test_GetJob_args(tctx, b, handle, *job_id, 1, &ginfo);
+               if (!ok) {
+                       torture_comment(tctx, "test_GetJob failed for JobId[%d]\n", *job_id);
+               }
+
                torture_comment(tctx, "Testing WritePrinter: Page[%d], JobId[%d]\n", i, *job_id);
 
                w.in.handle             = handle;
@@ -3490,7 +3531,7 @@ static bool test_DoPrintTest_check_jobs(struct torture_context *tctx,
                "AddJob failed");
 
        torture_assert(tctx,
-               test_EnumJobs_args(tctx, b, handle, 1, &count, &info),
+               test_EnumJobs_args(tctx, b, handle, 1, WERR_OK, &count, &info),
                "EnumJobs level 1 failed");
 
        torture_assert_int_equal(tctx, count, num_jobs, "unexpected number of jobs in queue");
@@ -3851,6 +3892,37 @@ static bool test_ResumePrinter(struct torture_context *tctx,
        return true;
 }
 
+static bool test_printer_purge(struct torture_context *tctx,
+                              struct dcerpc_binding_handle *b,
+                              struct policy_handle *handle)
+{
+       NTSTATUS status;
+       struct spoolss_SetPrinter r;
+       struct spoolss_SetPrinterInfoCtr info_ctr;
+       struct spoolss_DevmodeContainer devmode_ctr;
+       struct sec_desc_buf secdesc_ctr;
+
+       info_ctr.level = 0;
+       info_ctr.info.info0 = NULL;
+
+       ZERO_STRUCT(devmode_ctr);
+       ZERO_STRUCT(secdesc_ctr);
+
+       r.in.handle             = handle;
+       r.in.info_ctr           = &info_ctr;
+       r.in.devmode_ctr        = &devmode_ctr;
+       r.in.secdesc_ctr        = &secdesc_ctr;
+       r.in.command            = SPOOLSS_PRINTER_CONTROL_PURGE;
+
+       torture_comment(tctx, "Testing SetPrinter: SPOOLSS_PRINTER_CONTROL_PURGE\n");
+
+       status = dcerpc_spoolss_SetPrinter_r(b, tctx, &r);
+       torture_assert_ntstatus_ok(tctx, status, "SetPrinter failed");
+       torture_assert_werr_ok(tctx, r.out.result, "SetPrinter failed");
+
+       return true;
+}
+
 static bool test_GetPrinterData_checktype(struct torture_context *tctx,
                                          struct dcerpc_binding_handle *b,
                                          struct policy_handle *handle,
@@ -6135,7 +6207,7 @@ static bool test_SecondaryClosePrinter(struct torture_context *tctx,
                                       struct policy_handle *handle)
 {
        NTSTATUS status;
-       struct dcerpc_binding *b;
+       const struct dcerpc_binding *binding2;
        struct dcerpc_pipe *p2;
        struct spoolss_ClosePrinter cp;
 
@@ -6146,10 +6218,8 @@ static bool test_SecondaryClosePrinter(struct torture_context *tctx,
 
        torture_comment(tctx, "Testing close on secondary pipe\n");
 
-       status = dcerpc_parse_binding(tctx, p->conn->binding_string, &b);
-       torture_assert_ntstatus_ok(tctx, status, "Failed to parse dcerpc binding");
-
-       status = dcerpc_secondary_connection(p, &p2, b);
+       binding2 = p->binding;
+       status = dcerpc_secondary_connection(p, &p2, binding2);
        torture_assert_ntstatus_ok(tctx, status, "Failed to create secondary connection");
 
        status = dcerpc_bind_auth_none(p2, &ndr_table_spoolss);
@@ -8246,7 +8316,8 @@ static bool test_print_test_smbd(struct torture_context *tctx,
 
        /* check back end spoolss job was created */
        torture_assert(tctx,
-               test_EnumJobs_args(tctx, b, &t->handle, 1, &count, &info),
+               test_EnumJobs_args(tctx, b, &t->handle, 1, WERR_OK,
+                                  &count, &info),
                "EnumJobs level 1 failed");
 
        for (i = 0; i < count; i++) {
@@ -8265,6 +8336,60 @@ static bool test_print_test_smbd(struct torture_context *tctx,
        return true;
 }
 
+static bool test_print_test_purge(struct torture_context *tctx,
+                                 void *private_data)
+{
+       struct torture_printer_context *t =
+          (struct torture_printer_context *)talloc_get_type_abort(private_data,
+                                               struct torture_printer_context);
+       struct dcerpc_pipe *p = t->spoolss_pipe;
+       struct dcerpc_binding_handle *b = p->binding_handle;
+       uint32_t num_jobs = 8;
+       uint32_t *job_ids;
+       int i;
+       bool ret = true;
+       uint32_t count;
+       union spoolss_JobInfo *info;
+
+       torture_assert(tctx,
+               test_PausePrinter(tctx, b, &t->handle),
+               "failed to pause printer");
+
+       job_ids = talloc_zero_array(tctx, uint32_t, num_jobs);
+       for (i=0; i < num_jobs; i++) {
+               ret = test_DoPrintTest_add_one_job(tctx, b, &t->handle,
+                                                  "TorturePrintJob",
+                                                  &job_ids[i]);
+               torture_assert(tctx, ret, "failed to add print job");
+       }
+
+       torture_assert(tctx,
+               test_EnumJobs_args(tctx, b, &t->handle, 1, WERR_OK,
+                                  &count, &info),
+               "EnumJobs level 1 failed");
+
+       torture_assert_int_equal(tctx, count, num_jobs,
+                                "unexpected number of jobs in queue");
+
+       torture_assert(tctx,
+               test_printer_purge(tctx, b, &t->handle),
+               "failed to purge printer");
+
+       torture_assert(tctx,
+               test_EnumJobs_args(tctx, b, &t->handle, 1, WERR_OK,
+                                  &count, &info),
+               "EnumJobs level 1 failed");
+
+       torture_assert_int_equal(tctx, count, 0,
+                                "unexpected number of jobs in queue");
+
+       torture_assert(tctx,
+               test_ResumePrinter(tctx, b, &t->handle),
+               "failed to resume printer");
+
+       return true;
+}
+
 static bool test_printer_sd(struct torture_context *tctx,
                            void *private_data)
 {
@@ -8732,6 +8857,86 @@ static bool test_driver_info_winreg(struct torture_context *tctx,
        return true;
 }
 
+static bool test_print_job_enum(struct torture_context *tctx,
+                               void *private_data)
+{
+       struct torture_printer_context *t =
+               (struct torture_printer_context *)talloc_get_type_abort(private_data, struct torture_printer_context);
+       struct dcerpc_pipe *p = t->spoolss_pipe;
+       struct dcerpc_binding_handle *b = p->binding_handle;
+       bool ret = true;
+       uint32_t num_jobs = 8;
+       uint32_t *job_ids;
+       int i;
+       union spoolss_JobInfo *info = NULL;
+       uint32_t count;
+
+       torture_assert(tctx,
+               test_PausePrinter(tctx, b, &t->handle),
+               "failed to pause printer");
+
+       /* purge in case of any jobs from previous tests */
+       torture_assert(tctx,
+               test_printer_purge(tctx, b, &t->handle),
+               "failed to purge printer");
+
+       /* enum before jobs, valid level */
+       torture_assert(tctx,
+                      test_EnumJobs_args(tctx, b, &t->handle, 1, WERR_OK,
+                                         &count, &info),
+                      "EnumJobs with valid level");
+       torture_assert_int_equal(tctx, count, 0, "EnumJobs count");
+       torture_assert(tctx,
+                      test_EnumJobs_args(tctx, b, &t->handle, 2, WERR_OK,
+                                         &count, &info),
+                      "EnumJobs with valid level");
+       torture_assert_int_equal(tctx, count, 0, "EnumJobs count");
+       /* enum before jobs, invalid level - expect failure */
+       torture_assert(tctx,
+                      test_EnumJobs_args(tctx, b, &t->handle, 100,
+                                         WERR_INVALID_LEVEL,
+                                         &count, &info),
+                      "EnumJobs with invalid level");
+
+       job_ids = talloc_zero_array(tctx, uint32_t, num_jobs);
+
+       for (i = 0; i < num_jobs; i++) {
+               ret = test_DoPrintTest_add_one_job(tctx, b, &t->handle,
+                                                   "TorturePrintJob",
+                                                   &job_ids[i]);
+               torture_assert(tctx, ret, "failed to add print job");
+       }
+
+       /* enum after jobs, valid level */
+       torture_assert(tctx,
+                      test_EnumJobs_args(tctx, b, &t->handle, 1, WERR_OK,
+                                         &count, &info),
+                      "EnumJobs with valid level");
+       torture_assert_int_equal(tctx, count, num_jobs, "EnumJobs count");
+       torture_assert(tctx,
+                      test_EnumJobs_args(tctx, b, &t->handle, 2, WERR_OK,
+                                         &count, &info),
+                      "EnumJobs with valid level");
+       torture_assert_int_equal(tctx, count, num_jobs, "EnumJobs count");
+       /* enum after jobs, invalid level - expect failure */
+       torture_assert(tctx,
+                      test_EnumJobs_args(tctx, b, &t->handle, 100,
+                                         WERR_INVALID_LEVEL,
+                                         &count, &info),
+                      "EnumJobs with invalid level");
+
+       for (i = 0; i < num_jobs; i++) {
+               test_SetJob(tctx, b, &t->handle, job_ids[i], NULL,
+                           SPOOLSS_JOB_CONTROL_DELETE);
+       }
+
+       torture_assert(tctx,
+               test_ResumePrinter(tctx, b, &t->handle),
+               "failed to resume printer");
+
+       return true;
+}
+
 void torture_tcase_printer(struct torture_tcase *tcase)
 {
        torture_tcase_add_simple_test(tcase, "openprinter", test_openprinter_wrap);
@@ -8740,6 +8945,7 @@ void torture_tcase_printer(struct torture_tcase *tcase)
        torture_tcase_add_simple_test(tcase, "print_test_extended", test_print_test_extended);
        torture_tcase_add_simple_test(tcase, "print_test_smbd", test_print_test_smbd);
        torture_tcase_add_simple_test(tcase, "print_test_properties", test_print_test_properties);
+       torture_tcase_add_simple_test(tcase, "print_test_purge", test_print_test_purge);
        torture_tcase_add_simple_test(tcase, "printer_info", test_printer_info);
        torture_tcase_add_simple_test(tcase, "sd", test_printer_sd);
        torture_tcase_add_simple_test(tcase, "dm", test_printer_dm);
@@ -8758,6 +8964,7 @@ void torture_tcase_printer(struct torture_tcase *tcase)
        torture_tcase_add_simple_test(tcase, "bidi", test_printer_bidi);
        torture_tcase_add_simple_test(tcase, "publish_toggle",
                                      test_printer_publish_toggle);
+       torture_tcase_add_simple_test(tcase, "print_job_enum", test_print_job_enum);
 }
 
 struct torture_suite *torture_rpc_spoolss_printer(TALLOC_CTX *mem_ctx)