<commit_before>/*
 * This file is part of Cockpit.
 *
 * Copyright (C) 2013 Red Hat, Inc.
 *
 * Cockpit is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * Cockpit is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
 */

#include "config.h"

#include "mock-auth.h"
#include "cockpitws.h"
#include "cockpitcreds.h"
#include "cockpitwebservice.h"

#include "common/cockpitpipetransport.h"
#include "common/cockpittransport.h"
#include "common/cockpitjson.h"
#include "common/cockpittest.h"
#include "common/mock-io-stream.h"
#include "common/cockpitwebserver.h"
#include "common/cockpitconf.h"

#include "websocket/websocket.h"

#include <glib.h>

#include <libssh/libssh.h>

#include <string.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>

#define TIMEOUT 30

#define WAIT_UNTIL(cond) \
  G_STMT_START \
    while (!(cond)) g_main_context_iteration (NULL, TRUE); \
  G_STMT_END

#define PASSWORD "<PASSWORD>"

typedef struct {
  /* setup_mock_sshd */
  const gchar *ssh_user;
  const gchar *ssh_password;
  GPid mock_sshd;
  guint16 ssh_port;

  /* setup_mock_webserver */
  CockpitWebServer *web_server;
  gchar *cookie;
  CockpitAuth *auth;
  CockpitCreds *creds;

  /* setup_io_pair */
  GIOStream *io_a;
  GIOStream *io_b;

  /* serve_socket */
  CockpitWebService *service;
} TestCase;

typedef struct {
  WebSocketFlavor web_socket_flavor;
  const char *origin;
  const char *config;
} TestFixture;

static GString *
read_all_into_string (int fd)
{
  GString *input = g_string_new ("");
  gsize len;
  gssize ret;

  for (;;)
    {
      len = input->len;
      g_string_set_size (input, len + 256);
      ret = read (fd, input->str + len, 256);
      if (ret < 0)
        {
          if (errno != EAGAIN)
            {
              g_critical ("couldn't read from mock input: %s", g_strerror (errno));
              g_string_free (input, TRUE);
              return NULL;
            }
        }
      else if (ret == 0)
        {
          return input;
        }
      else
        {
          input->len = len + ret;
          input->str[input->len] = '\0';
        }
    }
}

static void
start_mock_sshd (const gchar *user,
                 const gchar *password,
                 GPid *out_pid,
                 gushort *out_port)
{
  GError *error = NULL;
  GString *port;
  gchar *endptr;
  guint64 value;
  gint out_fd;

  const gchar *argv[] = {
      BUILDDIR "/mock-sshd",
      "--user", user,
      "--password", password,
      NULL
  };

  g_spawn_async_with_pipes (BUILDDIR, (gchar **)argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL,
                            out_pid, NULL, &out_fd, NULL, &error);
  g_assert_no_error (error);

  /*
   * mock-sshd prints its port on stdout, and then closes stdout
   * This also lets us know when it has initialized.
   */

  port = read_all_into_string (out_fd);
  g_assert (port != NULL);
  close (out_fd);
  g_assert_no_error (error);

  g_strstrip (port->str);
  value = g_ascii_strtoull (port->str, &endptr, 10);
  if (!endptr || *endptr != '\0' || value == 0 || value > G_MAXUSHORT)
      g_critical ("invalid port printed by mock-sshd: %s", port->str);

  *out_port = (gushort)value;
  g_string_free (port, TRUE);
}

static void
setup_mock_sshd (TestCase *test,
                 gconstpointer data)
{
  start_mock_sshd (test->ssh_user ? test->ssh_user : g_get_user_name (),
                   test->ssh_password ? test->ssh_password : PASSWORD,
                   &test->mock_sshd,
                   &test->ssh_port);

  cockpit_ws_specific_ssh_port = test->ssh_port;

  cockpit_ws_known_hosts = SRCDIR "/src/ws/mock_known_hosts";
}

static void
stop_mock_sshd (GPid mock_sshd) {
  GPid pid;
  int status;

  pid = waitpid (mock_sshd, &status, WNOHANG);
  g_assert_cmpint (pid, >=, 0);
  if (pid == 0)
    kill (mock_sshd, SIGTERM);
  else if (status != 0)
    {
      if (WIFSIGNALED (status))
        g_critical ("mock-sshd terminated: %d", WTERMSIG (status));
      else
        g_critical ("mock-sshd failed: %d", WEXITSTATUS (status));
    }
  g_spawn_close_pid (mock_sshd);
}<commit_msg>ws: Don't fail test-webservice if mock-sshd fails<commit_after>/*
 * This file is part of Cockpit.
 *
 * Copyright (C) 2013 Red Hat, Inc.
 *
 * Cockpit is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * Cockpit is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with Cockpit; If not, see <http://www.gnu.org/licenses/>.
 */

#include "config.h"

#include "mock-auth.h"
#include "cockpitws.h"
#include "cockpitcreds.h"
#include "cockpitwebservice.h"

#include "common/cockpitpipetransport.h"
#include "common/cockpittransport.h"
#include "common/cockpitjson.h"
#include "common/cockpittest.h"
#include "common/mock-io-stream.h"
#include "common/cockpitwebserver.h"
#include "common/cockpitconf.h"

#include "websocket/websocket.h"

#include <glib.h>

#include <libssh/libssh.h>

#include <string.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>

#define TIMEOUT 30

#define WAIT_UNTIL(cond) \
  G_STMT_START \
    while (!(cond)) g_main_context_iteration (NULL, TRUE); \
  G_STMT_END

#define PASSWORD "<PASSWORD>"

typedef struct {
  /* setup_mock_sshd */
  const gchar *ssh_user;
  const gchar *ssh_password;
  GPid mock_sshd;
  guint16 ssh_port;

  /* setup_mock_webserver */
  CockpitWebServer *web_server;
  gchar *cookie;
  CockpitAuth *auth;
  CockpitCreds *creds;

  /* setup_io_pair */
  GIOStream *io_a;
  GIOStream *io_b;

  /* serve_socket */
  CockpitWebService *service;
} TestCase;

typedef struct {
  WebSocketFlavor web_socket_flavor;
  const char *origin;
  const char *config;
} TestFixture;

static GString *
read_all_into_string (int fd)
{
  GString *input = g_string_new ("");
  gsize len;
  gssize ret;

  for (;;)
    {
      len = input->len;
      g_string_set_size (input, len + 256);
      ret = read (fd, input->str + len, 256);
      if (ret < 0)
        {
          if (errno != EAGAIN)
            {
              g_critical ("couldn't read from mock input: %s", g_strerror (errno));
              g_string_free (input, TRUE);
              return NULL;
            }
        }
      else if (ret == 0)
        {
          return input;
        }
      else
        {
          input->len = len + ret;
          input->str[input->len] = '\0';
        }
    }
}

static void
start_mock_sshd (const gchar *user,
                 const gchar *password,
                 GPid *out_pid,
                 gushort *out_port)
{
  GError *error = NULL;
  GString *port;
  gchar *endptr;
  guint64 value;
  gint out_fd;

  const gchar *argv[] = {
      BUILDDIR "/mock-sshd",
      "--user", user,
      "--password", password,
      NULL
  };

  g_spawn_async_with_pipes (BUILDDIR, (gchar **)argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL,
                            out_pid, NULL, &out_fd, NULL, &error);
  g_assert_no_error (error);

  /*
   * mock-sshd prints its port on stdout, and then closes stdout
   * This also lets us know when it has initialized.
   */

  port = read_all_into_string (out_fd);
  g_assert (port != NULL);
  close (out_fd);
  g_assert_no_error (error);

  g_strstrip (port->str);
  value = g_ascii_strtoull (port->str, &endptr, 10);
  if (!endptr || *endptr != '\0' || value == 0 || value > G_MAXUSHORT)
      g_critical ("invalid port printed by mock-sshd: %s", port->str);

  *out_port = (gushort)value;
  g_string_free (port, TRUE);
}

static void
setup_mock_sshd (TestCase *test,
                 gconstpointer data)
{
  start_mock_sshd (test->ssh_user ? test->ssh_user : g_get_user_name (),
                   test->ssh_password ? test->ssh_password : PASSWORD,
                   &test->mock_sshd,
                   &test->ssh_port);

  cockpit_ws_specific_ssh_port = test->ssh_port;

  cockpit_ws_known_hosts = SRCDIR "/src/ws/mock_known_hosts";
}

static void
stop_mock_sshd (GPid mock_sshd) {
  GPid pid;
  int status;

  pid = waitpid (mock_sshd, &status, WNOHANG);
  g_assert_cmpint (pid, >=, 0);
  if (pid == 0)
    kill (mock_sshd, SIGTERM);
  else if (status != 0)
    {
      if (WIFSIGNALED (status))
        g_message ("mock-sshd terminated: %d", WTERMSIG (status));
      else
        g_message ("mock-sshd failed: %d", WEXITSTATUS (status));
    }
  g_spawn_close_pid (mock_sshd);
}
{'fraction_non_alphanumeric': 0.1192522561237645, 'fraction_numerical': 0.006016330038676407, 'mean_word_length': 2.8198604842018877, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 55, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2610447', 'n_tokens_mistral': 3423, 'n_tokens_neox': 3255, 'n_words': 882}