<commit_before>package proxmox

import (
	"strings"
	"testing"

	"github.com/hashicorp/packer/packer"
	"github.com/hashicorp/packer/template"
)

func mandatoryConfig(t *testing.T) map[string]interface{} {
	return map[string]interface{}{
		"proxmox_url":  "https://my-proxmox.my-domain:8006/api2/json",
		"username":     "apiuser@pve",
		"password":     "<PASSWORD>",
		"iso_file":     "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso",
		"node":         "my-proxmox",
		"ssh_username": "root",
	}
}

func TestRequiredParameters(t *testing.T) {
	var c Config
	_, err := c.Prepare(make(map[string]interface{}))
	if err == nil {
		t.Fatal("Expected empty configuration to fail")
	}
	errs, ok := err.(*packer.MultiError)
	if !ok {
		t.Fatal("Expected errors to be packer.MultiError")
	}

	required := []string{"username", "password", "proxmox_url", "iso_file", "node", "ssh_username"}
	for _, param := range required {
		found := false
		for _, err := range errs.Errors {
			if strings.Contains(err.Error(), param) {
				found = true
				break
			}
		}
		if !found {
			t.Errorf("Expected error about missing parameter %q", required)
		}
	}
}

func TestBasicExampleFromDocsIsValid(t *testing.T) {
	const config = `{
  "builders": [
    {
      "type": "proxmox",
      "proxmox_url": "https://my-proxmox.my-domain:8006/api2/json",
      "insecure_skip_tls_verify": true,
      "username": "apiuser@pve",
      "password": "<PASSWORD>",

      "node": "my-proxmox",
      "network_adapters": [
        {
          "bridge": "vmbr0"
        }
      ],
      "disks": [
        {
          "type": "scsi",
          "disk_size": "5G",
          "storage_pool": "local-lvm",
          "storage_pool_type": "lvm"
        }
      ],

      "iso_file": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso",
      "http_directory":"config",
      "boot_wait": "10s",
      "boot_command": [
        "<up><tab> ip=dhcp inst.cmdline inst.ks=http://{{.HTTPIP}}:{{.HTTPPort}}/ks.cfg<enter>"
      ],

      "ssh_username": "root",
      "ssh_timeout": "15m",
      "ssh_password": "<PASSWORD>",

      "unmount_iso": true,
      "template_name": "fedora-29",
      "template_description": "Fedora 29-1.2, generated on {{ isotime \"2006-01-02T15:04:05Z\" }}"
    }
  ]
}`
	tpl, err := template.Parse(strings.NewReader(config))
	if err != nil {
		t.Fatal(err)
	}

	b := &Builder{}
	_, warn, err := b.Prepare(tpl.Builders["proxmox"].Config)
	if err != nil {
		t.Fatal(err, warn)
	}

	// The example config does not set a number of optional fields. Validate that:
	// Memory 0 is too small, using default: 512
	// Number of cores 0 is too small, using default: 1
	// Number of sockets 0 is too small, using default: 1
	// CPU type not set, using default 'kvm64'
	// OS not set, using default 'other'
	// NIC 0 model not set, using default 'e1000'
	// Disk 0 cache mode not set, using default 'none'
	// Agent not set, default is true
	// SCSI controller not set, using default 'lsi'
	// Firewall toggle not set, using default: 0

	if b.config.Memory != 512 {
		t.Errorf("Expected Memory to be 512, got %d", b.config.Memory)
	}
	if b.config.Cores != 1 {
		t.Errorf("Expected Cores to be 1, got %d", b.config.Cores)
	}
	if b.config.Sockets != 1 {
		t.Errorf("Expected Sockets to be 1, got %d", b.config.Sockets)
	}
	if b.config.CPUType != "kvm64" {
		t.Errorf("Expected CPU type to be 'kvm64', got %s", b.config.CPUType)
	}
	if b.config.OS != "other" {
		t.Errorf("Expected OS to be 'other', got %s", b.config.OS)
	}
	if b.config.NICs[0].Model != "e1000" {
		t.Errorf("Expected NIC model to be 'e1000', got %s", b.config.NICs[0].Model)
	}
	if b.config.NICs[0].Firewall != false {
		t.Errorf("Expected NIC firewall to be false, got %t", b.config.NICs[0].Firewall)
	}
	if b.config.Disks[0].CacheMode != "none" {
		t.Errorf("Expected disk cache mode to be 'none', got %s", b.config.Disks[0].CacheMode)
	}
	if b.config.Agent != true {
		t.Errorf("Expected Agent to be true, got %t", b.config.Agent)
	}
	if b.config.SCSIController != "lsi" {
		t.Errorf("Expected SCSI controller to be 'lsi', got %s", b.config.SCSIController)
	}
	if b.config.CloudInit != false {
		t.Errorf("Expected CloudInit to be false, got %t", b.config.CloudInit)
	}
}

func TestAgentSetToFalse(t *testing.T) {
	// only the mandatory attributes are specified
	const config = `{
		"builders": [
			{
				"type": "proxmox",
				"proxmox_url": "https://my-proxmox.my-domain:8006/api2/json",
				"username": "apiuser@pve",
				"password": "<PASSWORD>",
				"iso_file": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso",
				"ssh_username": "root",
				"node": "my-proxmox",
				"qemu_agent": false
			}
		]
	}`

	tpl, err := template.Parse(strings.NewReader(config))
	if err != nil {
		t.Fatal(err)
	}

	b := &Builder{}
	_, warn, err := b.Prepare(tpl.Builders["proxmox"].Config)
	if err != nil {
		t.Fatal(err, warn)
	}

	if b.config.Agent != false {
		t.Errorf("Expected Agent to be false, got %t", b.config.Agent)
	}
}

func TestNetworkAdapterPacketQueueSupport(t *testing.T) {
	drivertests := []struct {
		expectedToFail bool
		model          string
	}{
		{expectedToFail: false, model: "virtio"},
		{expectedToFail: true, model: "e1000"},
		{expectedToFail: true, model: "e1000-82540em"},
		{expectedToFail: true, model: "e1000-82544gc"},
		{expectedToFail: true, model: "e1000-82545em"},
		{expectedToFail: true, model: "i82551"},
		{expectedToFail: true, model: "i82557b"},
		{expectedToFail: true, model: "i82559er"},
		{expectedToFail: true, model: "ne2k_isa"},
		{expectedToFail: true, model: "ne2k_pci"},
		{expectedToFail: true, model: "pcnet"},
		{expectedToFail: true, model: "rtl8139"},
		{expectedToFail: true, model: "vmxnet3"},
	}

	for _, tt := range drivertests {
		device := make(map[string]interface{})
		device["bridge"] = "vmbr0"
		device["model"] = tt.model
		device["packet_queues"] = 2

		devices := make([]map[string]interface{}, 0)
		devices = append(devices, device)
<commit_msg>use helper method for mandatory config<commit_after>package proxmox

import (
	"strings"
	"testing"

	"github.com/hashicorp/packer/packer"
	"github.com/hashicorp/packer/template"
)

func mandatoryConfig(t *testing.T) map[string]interface{} {
	return map[string]interface{}{
		"proxmox_url":  "https://my-proxmox.my-domain:8006/api2/json",
		"username":     "apiuser@pve",
		"password":     "<PASSWORD>",
		"iso_file":     "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso",
		"node":         "my-proxmox",
		"ssh_username": "root",
	}
}

func TestRequiredParameters(t *testing.T) {
	var c Config
	_, err := c.Prepare(make(map[string]interface{}))
	if err == nil {
		t.Fatal("Expected empty configuration to fail")
	}
	errs, ok := err.(*packer.MultiError)
	if !ok {
		t.Fatal("Expected errors to be packer.MultiError")
	}

	required := []string{"username", "password", "proxmox_url", "iso_file", "node", "ssh_username"}
	for _, param := range required {
		found := false
		for _, err := range errs.Errors {
			if strings.Contains(err.Error(), param) {
				found = true
				break
			}
		}
		if !found {
			t.Errorf("Expected error about missing parameter %q", required)
		}
	}
}

func TestBasicExampleFromDocsIsValid(t *testing.T) {
	const config = `{
  "builders": [
    {
      "type": "proxmox",
      "proxmox_url": "https://my-proxmox.my-domain:8006/api2/json",
      "insecure_skip_tls_verify": true,
      "username": "apiuser@pve",
      "password": "<PASSWORD>",

      "node": "my-proxmox",
      "network_adapters": [
        {
          "bridge": "vmbr0"
        }
      ],
      "disks": [
        {
          "type": "scsi",
          "disk_size": "5G",
          "storage_pool": "local-lvm",
          "storage_pool_type": "lvm"
        }
      ],

      "iso_file": "local:iso/Fedora-Server-dvd-x86_64-29-1.2.iso",
      "http_directory":"config",
      "boot_wait": "10s",
      "boot_command": [
        "<up><tab> ip=dhcp inst.cmdline inst.ks=http://{{.HTTPIP}}:{{.HTTPPort}}/ks.cfg<enter>"
      ],

      "ssh_username": "root",
      "ssh_timeout": "15m",
      "ssh_password": "<PASSWORD>",

      "unmount_iso": true,
      "template_name": "fedora-29",
      "template_description": "Fedora 29-1.2, generated on {{ isotime \"2006-01-02T15:04:05Z\" }}"
    }
  ]
}`
	tpl, err := template.Parse(strings.NewReader(config))
	if err != nil {
		t.Fatal(err)
	}

	b := &Builder{}
	_, warn, err := b.Prepare(tpl.Builders["proxmox"].Config)
	if err != nil {
		t.Fatal(err, warn)
	}

	// The example config does not set a number of optional fields. Validate that:
	// Memory 0 is too small, using default: 512
	// Number of cores 0 is too small, using default: 1
	// Number of sockets 0 is too small, using default: 1
	// CPU type not set, using default 'kvm64'
	// OS not set, using default 'other'
	// NIC 0 model not set, using default 'e1000'
	// Disk 0 cache mode not set, using default 'none'
	// Agent not set, default is true
	// SCSI controller not set, using default 'lsi'
	// Firewall toggle not set, using default: 0

	if b.config.Memory != 512 {
		t.Errorf("Expected Memory to be 512, got %d", b.config.Memory)
	}
	if b.config.Cores != 1 {
		t.Errorf("Expected Cores to be 1, got %d", b.config.Cores)
	}
	if b.config.Sockets != 1 {
		t.Errorf("Expected Sockets to be 1, got %d", b.config.Sockets)
	}
	if b.config.CPUType != "kvm64" {
		t.Errorf("Expected CPU type to be 'kvm64', got %s", b.config.CPUType)
	}
	if b.config.OS != "other" {
		t.Errorf("Expected OS to be 'other', got %s", b.config.OS)
	}
	if b.config.NICs[0].Model != "e1000" {
		t.Errorf("Expected NIC model to be 'e1000', got %s", b.config.NICs[0].Model)
	}
	if b.config.NICs[0].Firewall != false {
		t.Errorf("Expected NIC firewall to be false, got %t", b.config.NICs[0].Firewall)
	}
	if b.config.Disks[0].CacheMode != "none" {
		t.Errorf("Expected disk cache mode to be 'none', got %s", b.config.Disks[0].CacheMode)
	}
	if b.config.Agent != true {
		t.Errorf("Expected Agent to be true, got %t", b.config.Agent)
	}
	if b.config.SCSIController != "lsi" {
		t.Errorf("Expected SCSI controller to be 'lsi', got %s", b.config.SCSIController)
	}
	if b.config.CloudInit != false {
		t.Errorf("Expected CloudInit to be false, got %t", b.config.CloudInit)
	}
}

func TestAgentSetToFalse(t *testing.T) {
	cfg := mandatoryConfig(t)
	cfg["qemu_agent"] = false

	var c Config
	warn, err := c.Prepare(cfg)
	if err != nil {
		t.Fatal(err, warn)
	}

	if c.Agent != false {
		t.Errorf("Expected Agent to be false, got %t", c.Agent)
	}
}

func TestPacketQueueSupportForNetworkAdapters(t *testing.T) {
	drivertests := []struct {
		expectedToFail bool
		model          string
	}{
		{expectedToFail: false, model: "virtio"},
		{expectedToFail: true, model: "e1000"},
		{expectedToFail: true, model: "e1000-82540em"},
		{expectedToFail: true, model: "e1000-82544gc"},
		{expectedToFail: true, model: "e1000-82545em"},
		{expectedToFail: true, model: "i82551"},
		{expectedToFail: true, model: "i82557b"},
		{expectedToFail: true, model: "i82559er"},
		{expectedToFail: true, model: "ne2k_isa"},
		{expectedToFail: true, model: "ne2k_pci"},
		{expectedToFail: true, model: "pcnet"},
		{expectedToFail: true, model: "rtl8139"},
		{expectedToFail: true, model: "vmxnet3"},
	}

	for _, tt := range drivertests {
		device := make(map[string]interface{})
		device["bridge"] = "vmbr0"
		device["model"] = tt.model
		device["packet_queues"] = 2

		devices := make([]map[string]interface{}, 0)
		devices = append(devices, device)

{'fraction_non_alphanumeric': 0.17146356399265156, 'fraction_numerical': 0.027906569853906046, 'mean_word_length': 3.3817554618627828, 'pattern_counts': {'":': 69, '<': 16, '<?xml version=': 0, '>': 16, 'https://': 5, 'lorem ipsum': 0, 'www.': 0, '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': '5500365', 'n_tokens_mistral': 4661, 'n_tokens_neox': 4277, 'n_words': 998}