<commit_before>package digitalocean

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/pearkes/digitalocean"
)

func resourceDigitalOceanDroplet() *schema.Resource {
	return &schema.Resource{
		Create: resourceDigitalOceanDropletCreate,
		Read:   resourceDigitalOceanDropletRead,
		Update: resourceDigitalOceanDropletUpdate,
		Delete: resourceDigitalOceanDropletDelete,

		Schema: map[string]*schema.Schema{
			"image": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"region": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"size": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"status": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"locked": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"backups": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},

			"ipv6": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
			},

			"ipv6_address": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"ipv6_address_private": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"private_networking": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
			},

			"ipv4_address": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"ipv4_address_private": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"ssh_keys": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},

			"user_data": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
		},
	}
}

func resourceDigitalOceanDropletCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)

	// Build up our creation options
	opts := &digitalocean.CreateDroplet{
		Image:  d.Get("image").(string),
		Name:   d.Get("name").(string),
		Region: d.Get("region").(string),
		Size:   d.Get("size").(string),
	}

	if attr, ok := d.GetOk("backups"); ok {
		opts.Backups = attr.(string)
	}

	if attr, ok := d.GetOk("ipv6"); ok && attr.(bool) {
		opts.IPV6 = "true"
	}

	if attr, ok := d.GetOk("private_networking"); ok && attr.(bool) {
		opts.PrivateNetworking = "true"
	}

	if attr, ok := d.GetOk("user_data"); ok {
		opts.UserData = attr.(string)
	}

	// Get configured ssh_keys
	ssh_keys := d.Get("ssh_keys.#").(int)
	if ssh_keys > 0 {
		opts.SSHKeys = make([]string, 0, ssh_keys)
		for i := 0; i < ssh_keys; i++ {
			key := fmt.Sprintf("ssh_keys.%d", i)
			opts.SSHKeys = append(opts.SSHKeys, d.Get(key).(string))
		}
	}

	log.Printf("[DEBUG] Droplet create configuration: %#v", opts)

	id, err := client.CreateDroplet(opts)

	if err != nil {
		return fmt.Errorf("Error creating droplet: %s", err)
	}

	// Assign the droplets id
	d.SetId(id)

	log.Printf("[INFO] Droplet ID: %s", d.Id())

	_, err = WaitForDropletAttribute(d, "active", []string{"new"}, "status", meta)

	if err != nil {
		return fmt.Errorf(
			"Error waiting for droplet (%s) to become ready: %s", d.Id(), err)
	}

	return resourceDigitalOceanDropletRead(d, meta)
}

func resourceDigitalOceanDropletRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)

	// Retrieve the droplet properties for updating the state
	droplet, err := client.RetrieveDroplet(d.Id())

	if err != nil {
		return fmt.Errorf("Error retrieving droplet: %s", err)
	}

	if droplet.ImageSlug() == "" && droplet.ImageId() != "" {
		d.Set("image", droplet.ImageId())
	} else {
		d.Set("image", droplet.ImageSlug())
	}

	d.Set("name", droplet.Name)
	d.Set("region", droplet.RegionSlug())
	d.Set("size", droplet.SizeSlug)
	d.Set("status", droplet.Status)
	d.Set("locked", droplet.IsLocked())

	if droplet.IPV6Address("public") != "" {
		d.Set("ipv6", true)
		d.Set("ipv6_address", droplet.IPV6Address("public"))
		d.Set("ipv6_address_private", droplet.IPV6Address("private"))
	}

	d.Set("ipv4_address", droplet.IPV4Address("public"))

	if droplet.NetworkingType() == "private" {
		d.Set("private_networking", true)
		d.Set("ipv4_address_private", droplet.IPV4Address("private"))
	}

	// Initialize the connection info
	d.SetConnInfo(map[string]string{
		"type": "ssh",
		"host": droplet.IPV4Address("public"),
	})

	return nil
}

func resourceDigitalOceanDropletUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)

	if d.HasChange("size") {
		oldSize, newSize := d.GetChange("size")

		err := client.PowerOff(d.Id())

		if err != nil && !strings.Contains(err.Error(), "Droplet is already powered off") {
			return fmt.Errorf(
				"Error powering off droplet (%s): %s", d.Id(), err)
		}

		// Wait for power off
		_, err = WaitForDropletAttribute(d, "off", []string{"active"}, "status", client)

		if err != nil {
			return fmt.Errorf(
				"Error waiting for droplet (%s) to become powered off: %s", d.Id(), err)
		}

		// Resize the droplet
		err = client.Resize(d.Id(), newSize.(string))

		if err != nil {
			newErr := power_on_and_wait(d, meta)
			if newErr != nil {
				return fmt.Errorf(
					"Error powering on droplet (%s) after failed resize: %s", d.Id(), err)
			}
			return fmt.Errorf(
				"Error resizing droplet (%s): %s", d.Id(), err)
		}

		// Wait for the size to change
		_, err = WaitForDropletAttribute(
			d, newSize.(string), []string{"", oldSize.(string)}, "size", meta)

		if err != nil {
			newErr := power_on_and_wait(d, meta)
			if newErr != nil {
				return fmt.Errorf(
					"Error powering on droplet (%s) after waiting for resize to finish: %s", d.Id(), err)
			}
			return fmt.Errorf(
				"Error waiting for resize droplet (%s) to finish: %s", d.Id(), err)
		}

		err = client.PowerOn(d.Id())

		if err != nil {
			return fmt.Errorf(
				"Error powering on droplet (%s) after resize: %s", d.Id(), err)
		}

		// Wait for power off
		_, err = WaitForDropletAttribute(d, "active", []string{"off"}, "status", meta)

		if err != nil {
			return err
		}
	}

	if d.HasChange("name") {
		oldName, newName := d.GetChange("name")

		// Rename the droplet
		err := client.Rename(d.Id(), newName.(string))

		if err != nil {
			return fmt.Errorf(
				"Error renaming droplet (%s): %s", d.Id(), err)
		}

		// Wait for the name to change
		_, err = WaitForDropletAttribute(
			d, newName.(string), []string{"", oldName.(string)}, "name", meta)

		if err != nil {
			return fmt.Errorf(
				"Error waiting for rename droplet (%s) to finish: %s", d.Id(), err)
		}
	}

	// As there is no way to disable private networking,
	// we only check if it needs to be enabled
	if d.HasChange("private_networking") && d.Get("private_networking").(bool) {
		err := client.EnablePrivateNetworking(d.Id())

		if err != nil {
			return fmt.Errorf(
				"Error enabling private networking for droplet (%s): %s", d.Id(), err)
		}

		// Wait for the private_networking to turn on
		_, err = WaitForDropletAttribute(
			d, "true", []string{"", "false"}, "private_networking", meta)

		return fmt.Errorf(
			"Error waiting for private networking to be enabled on for droplet (%s): %s", d.Id(), err)
	}

	// As there is no way to disable IPv6, we only check if it needs to be enabled
	if d.HasChange("ipv6") && d.Get("ipv6").(bool) {
		err := client.EnableIPV6s(d.Id())

		if err != nil {
			return fmt.Errorf(
				"Error turning on ipv6 for droplet (%s): %s", d.Id(), err)
		}

		// Wait for ipv6 to turn on
		_, err = WaitForDropletAttribute(
			d, "true", []string{"", "false"}, "ipv6", meta)

		if err != nil {
			return fmt.Errorf(
				"Error waiting for ipv6 to be turned on for droplet (%s): %s", d.Id(), err)
		}
	}

	return resourceDigitalOceanDropletRead(d, meta)
}

func resourceDigitalOceanDropletDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)

	log.Printf("[INFO] Deleting droplet: %s", d.Id())

	// Destroy the droplet
	err := client.DestroyDroplet(d.Id())

	// Handle remotely destroyed droplets
	if err != nil && strings.Contains(err.Error(), "404 Not Found") {
		return nil
	}

	if err != nil {
		return fmt.Errorf("Error deleting droplet: %s", err)
	}

	return nil
}

func WaitForDropletAttribute(
	d *schema.ResourceData, target string, pending []string, attribute string, meta interface{}) (interface{}, error) {
	// Wait for the droplet so we can get the networking attributes
	// that show up after a while
	log.Printf(
		"[INFO] Waiting for droplet (%s) to have %s of %s",
		d.Id(), attribute, target)

	stateConf := &resource.StateChangeConf{
		Pending:    pending,
		Target:     target,
		Refresh:    new_droplet_state_refresh_func(d, attribute, meta),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	return stateConf.WaitForState()
}

// TODO This function still needs a little more refactoring to make it
// cleaner and more efficient
func new_droplet_state_refresh_func(
	d *schema.ResourceData, attribute string, meta interface{}) resource.StateRefreshFunc {
	client := meta.(*digitalocean.Client)
	return func() (interface{}, string, error) {
		err := resourceDigitalOceanDropletRead(d, meta)

		if err != nil {
			return nil, "", err
		}

		// If the droplet is locked, continue waiting. We can
		// only perform actions on unlocked droplets, so it's
		// pointless to look at that status
		if d.Get("locked").(string) == "true" {
			log.Println("[DEBUG] Droplet is locked, skipping status check and retrying")
			return nil, "", nil
		}

		// See if we can access our attribute
		if attr, ok := d.GetOk(attribute); ok {
			// Retrieve the droplet properties
			droplet, err := client.RetrieveDroplet(d.Id())

			if err != nil {
				return nil, "", fmt.Errorf("Error retrieving droplet: %s", err)
			}

			return &droplet, attr.(string), nil
		}

		return nil, "", nil
	}
}

// Powers on the droplet and waits for it to be active
func power_on_and_wait(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)
	err := client.PowerOn(d.Id())

	if err != nil {
		return err
	}

	// Wait for power on
	_, err = WaitForDropletAttribute(d, "active", []string{"off"}, "status", client)

	if err != nil {
		return err
	}

	return nil
}
<commit_msg>simplify digitalocean_droplet.image loading<commit_after>package digitalocean

import (
	"fmt"
	"log"
	"strings"
	"time"

	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/pearkes/digitalocean"
)

func resourceDigitalOceanDroplet() *schema.Resource {
	return &schema.Resource{
		Create: resourceDigitalOceanDropletCreate,
		Read:   resourceDigitalOceanDropletRead,
		Update: resourceDigitalOceanDropletUpdate,
		Delete: resourceDigitalOceanDropletDelete,

		Schema: map[string]*schema.Schema{
			"image": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"name": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"region": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"size": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},

			"status": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"locked": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"backups": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},

			"ipv6": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
			},

			"ipv6_address": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"ipv6_address_private": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"private_networking": &schema.Schema{
				Type:     schema.TypeBool,
				Optional: true,
			},

			"ipv4_address": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"ipv4_address_private": &schema.Schema{
				Type:     schema.TypeString,
				Computed: true,
			},

			"ssh_keys": &schema.Schema{
				Type:     schema.TypeList,
				Optional: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
			},

			"user_data": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
			},
		},
	}
}

func resourceDigitalOceanDropletCreate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)

	// Build up our creation options
	opts := &digitalocean.CreateDroplet{
		Image:  d.Get("image").(string),
		Name:   d.Get("name").(string),
		Region: d.Get("region").(string),
		Size:   d.Get("size").(string),
	}

	if attr, ok := d.GetOk("backups"); ok {
		opts.Backups = attr.(string)
	}

	if attr, ok := d.GetOk("ipv6"); ok && attr.(bool) {
		opts.IPV6 = "true"
	}

	if attr, ok := d.GetOk("private_networking"); ok && attr.(bool) {
		opts.PrivateNetworking = "true"
	}

	if attr, ok := d.GetOk("user_data"); ok {
		opts.UserData = attr.(string)
	}

	// Get configured ssh_keys
	ssh_keys := d.Get("ssh_keys.#").(int)
	if ssh_keys > 0 {
		opts.SSHKeys = make([]string, 0, ssh_keys)
		for i := 0; i < ssh_keys; i++ {
			key := fmt.Sprintf("ssh_keys.%d", i)
			opts.SSHKeys = append(opts.SSHKeys, d.Get(key).(string))
		}
	}

	log.Printf("[DEBUG] Droplet create configuration: %#v", opts)

	id, err := client.CreateDroplet(opts)

	if err != nil {
		return fmt.Errorf("Error creating droplet: %s", err)
	}

	// Assign the droplets id
	d.SetId(id)

	log.Printf("[INFO] Droplet ID: %s", d.Id())

	_, err = WaitForDropletAttribute(d, "active", []string{"new"}, "status", meta)

	if err != nil {
		return fmt.Errorf(
			"Error waiting for droplet (%s) to become ready: %s", d.Id(), err)
	}

	return resourceDigitalOceanDropletRead(d, meta)
}

func resourceDigitalOceanDropletRead(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)

	// Retrieve the droplet properties for updating the state
	droplet, err := client.RetrieveDroplet(d.Id())

	if err != nil {
		return fmt.Errorf("Error retrieving droplet: %s", err)
	}

	if droplet.ImageSlug() != "" {
		d.Set("image", droplet.ImageSlug())
	} else {
		d.Set("image", droplet.ImageId())
	}

	d.Set("name", droplet.Name)
	d.Set("region", droplet.RegionSlug())
	d.Set("size", droplet.SizeSlug)
	d.Set("status", droplet.Status)
	d.Set("locked", droplet.IsLocked())

	if droplet.IPV6Address("public") != "" {
		d.Set("ipv6", true)
		d.Set("ipv6_address", droplet.IPV6Address("public"))
		d.Set("ipv6_address_private", droplet.IPV6Address("private"))
	}

	d.Set("ipv4_address", droplet.IPV4Address("public"))

	if droplet.NetworkingType() == "private" {
		d.Set("private_networking", true)
		d.Set("ipv4_address_private", droplet.IPV4Address("private"))
	}

	// Initialize the connection info
	d.SetConnInfo(map[string]string{
		"type": "ssh",
		"host": droplet.IPV4Address("public"),
	})

	return nil
}

func resourceDigitalOceanDropletUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)

	if d.HasChange("size") {
		oldSize, newSize := d.GetChange("size")

		err := client.PowerOff(d.Id())

		if err != nil && !strings.Contains(err.Error(), "Droplet is already powered off") {
			return fmt.Errorf(
				"Error powering off droplet (%s): %s", d.Id(), err)
		}

		// Wait for power off
		_, err = WaitForDropletAttribute(d, "off", []string{"active"}, "status", client)

		if err != nil {
			return fmt.Errorf(
				"Error waiting for droplet (%s) to become powered off: %s", d.Id(), err)
		}

		// Resize the droplet
		err = client.Resize(d.Id(), newSize.(string))

		if err != nil {
			newErr := power_on_and_wait(d, meta)
			if newErr != nil {
				return fmt.Errorf(
					"Error powering on droplet (%s) after failed resize: %s", d.Id(), err)
			}
			return fmt.Errorf(
				"Error resizing droplet (%s): %s", d.Id(), err)
		}

		// Wait for the size to change
		_, err = WaitForDropletAttribute(
			d, newSize.(string), []string{"", oldSize.(string)}, "size", meta)

		if err != nil {
			newErr := power_on_and_wait(d, meta)
			if newErr != nil {
				return fmt.Errorf(
					"Error powering on droplet (%s) after waiting for resize to finish: %s", d.Id(), err)
			}
			return fmt.Errorf(
				"Error waiting for resize droplet (%s) to finish: %s", d.Id(), err)
		}

		err = client.PowerOn(d.Id())

		if err != nil {
			return fmt.Errorf(
				"Error powering on droplet (%s) after resize: %s", d.Id(), err)
		}

		// Wait for power off
		_, err = WaitForDropletAttribute(d, "active", []string{"off"}, "status", meta)

		if err != nil {
			return err
		}
	}

	if d.HasChange("name") {
		oldName, newName := d.GetChange("name")

		// Rename the droplet
		err := client.Rename(d.Id(), newName.(string))

		if err != nil {
			return fmt.Errorf(
				"Error renaming droplet (%s): %s", d.Id(), err)
		}

		// Wait for the name to change
		_, err = WaitForDropletAttribute(
			d, newName.(string), []string{"", oldName.(string)}, "name", meta)

		if err != nil {
			return fmt.Errorf(
				"Error waiting for rename droplet (%s) to finish: %s", d.Id(), err)
		}
	}

	// As there is no way to disable private networking,
	// we only check if it needs to be enabled
	if d.HasChange("private_networking") && d.Get("private_networking").(bool) {
		err := client.EnablePrivateNetworking(d.Id())

		if err != nil {
			return fmt.Errorf(
				"Error enabling private networking for droplet (%s): %s", d.Id(), err)
		}

		// Wait for the private_networking to turn on
		_, err = WaitForDropletAttribute(
			d, "true", []string{"", "false"}, "private_networking", meta)

		return fmt.Errorf(
			"Error waiting for private networking to be enabled on for droplet (%s): %s", d.Id(), err)
	}

	// As there is no way to disable IPv6, we only check if it needs to be enabled
	if d.HasChange("ipv6") && d.Get("ipv6").(bool) {
		err := client.EnableIPV6s(d.Id())

		if err != nil {
			return fmt.Errorf(
				"Error turning on ipv6 for droplet (%s): %s", d.Id(), err)
		}

		// Wait for ipv6 to turn on
		_, err = WaitForDropletAttribute(
			d, "true", []string{"", "false"}, "ipv6", meta)

		if err != nil {
			return fmt.Errorf(
				"Error waiting for ipv6 to be turned on for droplet (%s): %s", d.Id(), err)
		}
	}

	return resourceDigitalOceanDropletRead(d, meta)
}

func resourceDigitalOceanDropletDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)

	log.Printf("[INFO] Deleting droplet: %s", d.Id())

	// Destroy the droplet
	err := client.DestroyDroplet(d.Id())

	// Handle remotely destroyed droplets
	if err != nil && strings.Contains(err.Error(), "404 Not Found") {
		return nil
	}

	if err != nil {
		return fmt.Errorf("Error deleting droplet: %s", err)
	}

	return nil
}

func WaitForDropletAttribute(
	d *schema.ResourceData, target string, pending []string, attribute string, meta interface{}) (interface{}, error) {
	// Wait for the droplet so we can get the networking attributes
	// that show up after a while
	log.Printf(
		"[INFO] Waiting for droplet (%s) to have %s of %s",
		d.Id(), attribute, target)

	stateConf := &resource.StateChangeConf{
		Pending:    pending,
		Target:     target,
		Refresh:    new_droplet_state_refresh_func(d, attribute, meta),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	return stateConf.WaitForState()
}

// TODO This function still needs a little more refactoring to make it
// cleaner and more efficient
func new_droplet_state_refresh_func(
	d *schema.ResourceData, attribute string, meta interface{}) resource.StateRefreshFunc {
	client := meta.(*digitalocean.Client)
	return func() (interface{}, string, error) {
		err := resourceDigitalOceanDropletRead(d, meta)

		if err != nil {
			return nil, "", err
		}

		// If the droplet is locked, continue waiting. We can
		// only perform actions on unlocked droplets, so it's
		// pointless to look at that status
		if d.Get("locked").(string) == "true" {
			log.Println("[DEBUG] Droplet is locked, skipping status check and retrying")
			return nil, "", nil
		}

		// See if we can access our attribute
		if attr, ok := d.GetOk(attribute); ok {
			// Retrieve the droplet properties
			droplet, err := client.RetrieveDroplet(d.Id())

			if err != nil {
				return nil, "", fmt.Errorf("Error retrieving droplet: %s", err)
			}

			return &droplet, attr.(string), nil
		}

		return nil, "", nil
	}
}

// Powers on the droplet and waits for it to be active
func power_on_and_wait(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*digitalocean.Client)
	err := client.PowerOn(d.Id())

	if err != nil {
		return err
	}

	// Wait for power on
	_, err = WaitForDropletAttribute(d, "active", []string{"off"}, "status", client)

	if err != nil {
		return err
	}

	return nil
}
<|endoftext|>


<commit_before>package bzip2

import (
	"bytes"
	"compress/bzip2"
	"io"
	"io/ioutil"
	"testing"

	"github.com/larzconwell/bzip2/internal/testhelpers"
)

func TestWriteAfterClose(t *testing.T) {
	var buf bytes.Buffer
	writer := NewWriter(&buf)
	err := writer.Close()
	if err != nil {
		t.Fatal(err)
	}

	_, err = writer.Write([]byte{})
	if err != nil && err != ErrWriteAfterClose {
		t.Fatal(err)
	}

	if err == nil {
		t.Error("Write after closing should error but didn't")
	}

	// Minimally test reset.
	writer.Reset(&buf)
	_, err = writer.Write([]byte{})
	if err != nil && err != ErrWriteAfterClose {
		t.Fatal(err)
	}

	if err != nil {
		t.Error("Write after reset shouldn't return ErrWriterAfterClose but did")
	}
}

func TestEmptyValid(t *testing.T) {
	var buf bytes.Buffer
	writer := NewWriter(&buf)
	_, err := writer.Write([]byte{})
	if err == nil {
		err = writer.Close()
	}
	if err != nil {
		t.Fatal(err)
	}

	reader := bzip2.NewReader(&buf)
	_, err = io.Copy(ioutil.Discard, reader)
	if err != nil {
		t.Fatal(err)
	}
}

func TestIncompleteBlock(t *testing.T) {
	var buf bytes.Buffer
	var out bytes.Buffer
	expected := []byte("banana")

	writer := NewWriter(&buf)
	_, err := writer.Write(expected)
	if err == nil {
		err = writer.Close()
	}
	if err != nil {
		t.Fatal(err)
	}

	reader := bzip2.NewReader(&buf)
	_, err = io.Copy(&out, reader)
	if err != nil {
		t.Fatal(err)
	}

	if out.String() != string(expected) {
		t.Error("Output is incorrect. Got", out.String(), "wanted",
			string(expected))
	}
}

func TestFilledBlock(t *testing.T) {
	var buf bytes.Buffer
	var out bytes.Buffer
	expected := testhelpers.RandomRunData(baseBlockSize)

	writer := NewWriterLevel(&buf, 1)
	_, err := writer.Write(expected)
	if err == nil {
		err = writer.Close()
	}
	if err != nil {
		t.Fatal(err)
	}

	reader := bzip2.NewReader(&buf)
	_, err = io.Copy(&out, reader)
	if err != nil {
		t.Fatal(err)
	}

	if out.String() != string(expected) {
		t.Error("Output is incorrect.")
	}
}

func TestFilledNoRunsBlock(t *testing.T) {
	var buf bytes.Buffer
	var out bytes.Buffer
	expected := testhelpers.NoRunData(baseBlockSize)

	writer := NewWriterLevel(&buf, 1)
	_, err := writer.Write(expected)
	if err == nil {
		err = writer.Close()
	}
	if err != nil {
		t.Fatal(err)
	}

	reader := bzip2.NewReader(&buf)
	_, err = io.Copy(&out, reader)
	if err != nil {
		t.Fatal(err)
	}

	if out.String() != string(expected) {
		t.Error("Output is incorrect.")
	}
}

func TestMultiBlock(t *testing.T) {
	var buf bytes.Buffer
	var out bytes.Buffer
	expected := testhelpers.RandomRunData(2 * baseBlockSize)

	writer := NewWriterLevel(&buf, 1)
	_, err := writer.Write(expected)
	if err == nil {
		err = writer.Close()
	}
	if err != nil {
		t.Fatal(err)
	}

	reader := bzip2.NewReader(&buf)
	_, err = io.Copy(&out, reader)
	if err != nil {
		t.Fatal(err)
	}

	if out.String() != string(expected) {
		t.Error("Output is incorrect.")
	}
}
<commit_msg>Remove after close tests, and fix them.<commit_after>package bzip2

import (
	"bytes"
	"compress/bzip2"
	"io"
	"io/ioutil"
	"testing"

	"github.com/larzconwell/bzip2/internal/testhelpers"
)

func TestEmptyValid(t *testing.T) {
	var buf bytes.Buffer
	writer := NewWriter(&buf)
	_, err := writer.Write([]byte{})
	if err == nil {
		err = writer.Close()
	}
	if err != nil {
		t.Fatal(err)
	}

	reader := bzip2.NewReader(&buf)
	_, err = io.Copy(ioutil.Discard, reader)
	if err != nil {
		t.Fatal(err)
	}
}

func TestIncompleteBlock(t *testing.T) {
	var buf bytes.Buffer
	var out bytes.Buffer
	expected := []byte("banana")

	writer := NewWriter(&buf)
	_, err := writer.Write(expected)
	if err == nil {
		err = writer.Close()
	}
	if err != nil {
		t.Fatal(err)
	}

	reader := bzip2.NewReader(&buf)
	_, err = io.Copy(&out, reader)
	if err != nil {
		t.Fatal(err)
	}

	if out.String() != string(expected) {
		t.Error("Output is incorrect. Got", out.String(), "wanted",
			string(expected))
	}
}

func TestFilledBlock(t *testing.T) {
	var buf bytes.Buffer
	var out bytes.Buffer
	expected := testhelpers.RandomRunData(baseBlockSize)

	writer, _ := NewWriterLevel(&buf, 1)
	_, err := writer.Write(expected)
	if err == nil {
		err = writer.Close()
	}
	if err != nil {
		t.Fatal(err)
	}

	reader := bzip2.NewReader(&buf)
	_, err = io.Copy(&out, reader)
	if err != nil {
		t.Fatal(err)
	}

	if out.String() != string(expected) {
		t.Error("Output is incorrect.")
	}
}

func TestFilledNoRunsBlock(t *testing.T) {
	var buf bytes.Buffer
	var out bytes.Buffer
	expected := testhelpers.NoRunData(baseBlockSize)

	writer, _ := NewWriterLevel(&buf, 1)
	_, err := writer.Write(expected)
	if err == nil {
		err = writer.Close()
	}
	if err != nil {
		t.Fatal(err)
	}

	reader := bzip2.NewReader(&buf)
	_, err = io.Copy(&out, reader)
	if err != nil {
		t.Fatal(err)
	}

	if out.String() != string(expected) {
		t.Error("Output is incorrect.")
	}
}

func TestMultiBlock(t *testing.T) {
	var buf bytes.Buffer
	var out bytes.Buffer
	expected := testhelpers.RandomRunData(2 * baseBlockSize)

	writer, _ := NewWriterLevel(&buf, 1)
	_, err := writer.Write(expected)
	if err == nil {
		err = writer.Close()
	}
	if err != nil {
		t.Fatal(err)
	}

	reader := bzip2.NewReader(&buf)
	_, err = io.Copy(&out, reader)
	if err != nil {
		t.Fatal(err)
	}

	if out.String() != string(expected) {
		t.Error("Output is incorrect.")
	}
}
<|endoftext|>


<commit_before><commit_msg>scene: Added Documentation<commit_after><|endoftext|>


<commit_before>// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package vulncheck

import (
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"strings"

	"golang.org/x/tools/go/packages"
	"golang.org/x/vuln/client"
	"golang.org/x/vuln/osv"
)

// ResultVersion should change when the results of this package change
// for any input. It is intended to be used to cache results.
// The field should begin with a date in YYYY-MM-DD format.
// Experimental versions of the package should follow that with
// a brief description. E.g. "2022-08-03 CHA only".
const ResultVersion = "2022-07-21"

// Config is used for configuring vulncheck algorithms.
type Config struct {
	// ImportsOnly instructs vulncheck to analyze import chains only.
	// Otherwise, call chains are analyzed too.
	ImportsOnly bool

	// Client is used for querying data from a vulnerability database.
	Client client.Client

	// SourceGoVersion is Go version used to build Source inputs passed
	// to vulncheck. If not provided, the current underlying Go version
	// is used to detect vulnerabilities in Go standard library.
	SourceGoVersion string
}

// Package is a Go package for vulncheck analysis. It is a version of
// packages.Package trimmed down to reduce memory consumption.
type Package struct {
	Name      string
	PkgPath   string
	Imports   []*Package
	Pkg       *types.Package
	Fset      *token.FileSet
	Syntax    []*ast.File
	TypesInfo *types.Info
	Module    *Module
}

// Module is a Go module for vulncheck analysis.
type Module struct {
	Path    string
	Version string
	Dir     string
	Replace *Module
}

// Convert transforms a slice of packages.Package to
// a slice of corresponding vulncheck.Package.
func Convert(pkgs []*packages.Package) []*Package {
	convertMod := newModuleConverter()
	ps := make(map[*packages.Package]*Package)
	var pkg func(*packages.Package) *Package
	pkg = func(p *packages.Package) *Package {
		if vp, ok := ps[p]; ok {
			return vp
		}

		vp := &Package{
			Name:      p.Name,
			PkgPath:   p.PkgPath,
			Pkg:       p.Types,
			Fset:      p.Fset,
			Syntax:    p.Syntax,
			TypesInfo: p.TypesInfo,
			Module:    convertMod(p.Module),
		}
		ps[p] = vp

		for _, i := range p.Imports {
			vp.Imports = append(vp.Imports, pkg(i))
		}
		return vp
	}

	var vpkgs []*Package
	for _, p := range pkgs {
		vpkgs = append(vpkgs, pkg(p))
	}
	return vpkgs
}

// Result contains information on how known vulnerabilities are reachable
// in the call graph, package imports graph, and module requires graph of
// the user code.
type Result struct {
	// Calls is a call graph whose roots are program entry functions and
	// methods, and sinks are known vulnerable symbols. It is empty when
	// Config.ImportsOnly is true or when no vulnerable symbols are reachable
	// via the program call graph.
	Calls *CallGraph

	// Imports is a package dependency graph whose roots are entry user packages
	// and sinks are packages with some known vulnerable symbols. It is empty
	// when no packages with vulnerabilities are imported in the program.
	Imports *ImportGraph

	// Requires is a module dependency graph whose roots are entry user modules
	// and sinks are modules with some vulnerable packages. It is empty when no
	// modules with vulnerabilities are required by the program. If used, the
	// standard library is modeled as an artificial "stdlib" module whose version
	// is the Go version used to build the code under analysis.
	Requires *RequireGraph

	// Vulns contains information on detected vulnerabilities and their place in
	// the above graphs. Only vulnerabilities whose symbols are reachable in Calls,
	// or whose packages are imported in Imports, or whose modules are required in
	// Requires, have an entry in Vulns.
	Vulns []*Vuln

	// Modules are the modules that comprise the user code.
	Modules []*Module
}

// Vuln provides information on how a vulnerability is affecting user code by
// connecting it to the Result.{Calls,Imports,Requires} graphs. Vulnerabilities
// detected in Go binaries do not appear in the Result graphs.
type Vuln struct {
	// OSV contains information on the detected vulnerability in the shared
	// vulnerability format.
	//
	// OSV, Symbol, PkgPath, and ModPath identify a vulnerability.
	//
	// Note that *osv.Entry may describe multiple symbols from multiple
	// packages.
	OSV *osv.Entry

	// Symbol is the name of the detected vulnerable function or method.
	Symbol string

	// PkgPath is the package path of the detected Symbol.
	PkgPath string

	// ModPath is the module path corresponding to PkgPath.
	ModPath string

	// CallSink is the ID of the FuncNode in Result.Calls corresponding to
	// Symbol.
	//
	// When analyzing binaries, Symbol is not reachable, or Config.ImportsOnly
	// is true, CallSink will be unavailable and set to 0.
	CallSink int

	// ImportSink is the ID of the PkgNode in Result.Imports corresponding to
	// PkgPath.
	//
	// When analyzing binaries or PkgPath is not imported, ImportSink will be
	// unavailable and set to 0.
	ImportSink int

	// RequireSink is the ID of the ModNode in Result.Requires corresponding to
	// ModPath.
	//
	// When analyzing binaries, RequireSink will be unavailable and set to 0.
	RequireSink int
}

// CallGraph is a slice of a full program call graph whose sinks are vulnerable
// functions and sources are entry points of user packages.
//
// CallGraph is directed from vulnerable functions towards program entry
// functions (see FuncNode) for a more efficient traversal of the slice
// related to a particular vulnerability.
type CallGraph struct {
	// Functions contains all call graph nodes as a map: FuncNode.ID -> FuncNode.
	Functions map[int]*FuncNode

	// Entries are IDs of a subset of Functions representing vulncheck entry points.
	Entries []int
}

// A FuncNode describes a function in the call graph.
type FuncNode struct {
	// ID is the id used to identify the FuncNode in CallGraph.
	ID int

	// Name is the name of the function.
	Name string

	// RecvType is the receiver object type of this function, if any.
	RecvType string

	// PkgPath is the import path of the package containing the function.
	PkgPath string

	// Position describes the position of the function in the file.
	Pos *token.Position

	// CallSites is a set of call sites where this function is called.
	CallSites []*CallSite
}

func (fn *FuncNode) String() string {
	if fn.RecvType == "" {
		return fmt.Sprintf("%s.%s", fn.PkgPath, fn.Name)
	}
	return fmt.Sprintf("%s.%s", fn.RecvType, fn.Name)
}

// A CallSite describes a function call.
type CallSite struct {
	// Parent is ID of the enclosing function where the call is made.
	Parent int

	// Name stands for the name of the function (variable) being called.
	Name string

	// RecvType is the full path of the receiver object type, if any.
	RecvType string

	// Position describes the position of the function in the file.
	Pos *token.Position

	// Resolved indicates if the called function can be statically resolved.
	Resolved bool
}

// RequireGraph is a slice of a full program module requires graph whose sinks
// are modules with known vulnerabilities and sources are modules of user entry
// packages.
//
// RequireGraph is directed from a vulnerable module towards the program entry
// modules (see ModNode) for a more efficient traversal of the slice related
// to a particular vulnerability.
type RequireGraph struct {
	// Modules contains all module nodes as a map: module node id -> module node.
	Modules map[int]*ModNode

	// Entries are IDs of a subset of Modules representing modules of vulncheck entry points.
	Entries []int
}

// A ModNode describes a module in the requires graph.
type ModNode struct {
	// ID is the id used to identify the ModNode in CallGraph.
	ID int

	// Path is the module path.
	Path string

	// Version is the module version.
	Version string

	// Replace is the ID of the replacement module node.
	// A zero value means there is no replacement.
	Replace int

	// RequiredBy contains IDs of the modules requiring this module.
	RequiredBy []int
}

// ImportGraph is a slice of a full program package import graph whose sinks are
// packages with some known vulnerabilities and sources are user specified
// packages.
//
// ImportGraph is directed from a vulnerable package towards the program entry
// packages (see PkgNode) for a more efficient traversal of the slice related
// to a particular vulnerability.
type ImportGraph struct {
	// Packages contains all package nodes as a map: package node id -> package node.
	Packages map[int]*PkgNode

	// Entries are IDs of a subset of Packages representing packages of vulncheck entry points.
	Entries []int
}

// A PkgNode describes a package in the import graph.
type PkgNode struct {
	// ID is the id used to identify the PkgNode in ImportGraph.
	ID int

	// Name is the package identifier as it appears in the source code.
	Name string

	// Path is the package path.
	Path string

	// Module holds ID of the corresponding module (node) in the Requires graph.
	Module int

	// ImportedBy contains IDs of packages directly importing this package.
	ImportedBy []int

	// pkg is used for connecting package node to module and call graph nodes.
	pkg *Package
}

// moduleVulnerabilities is an internal structure for
// holding and querying vulnerabilities provided by a
// vulnerability database client.
type moduleVulnerabilities []modVulns

// modVulns groups vulnerabilities per module.
type modVulns struct {
	mod   *Module
	vulns []*osv.Entry
}

func (mv moduleVulnerabilities) filter(os, arch string) moduleVulnerabilities {
	var filteredMod moduleVulnerabilities
	for _, mod := range mv {
		module := mod.mod
		modVersion := module.Version
		if module.Replace != nil {
			modVersion = module.Replace.Version
		}
		// TODO(https://golang.org/issues/49264): if modVersion == "", try vcs?
		var filteredVulns []*osv.Entry
		for _, v := range mod.vulns {
			var filteredAffected []osv.Affected
			for _, a := range v.Affected {
				// A module version is affected if
				//  - it is included in one of the affected version ranges
				//  - and module version is not ""
				//  The latter means the module version is not available, so
				//  we don't want to spam users with potential false alarms.
				//  TODO: issue warning for "" cases above?
				affected := modVersion != "" && a.Ranges.AffectsSemver(modVersion) && matchesPlatform(os, arch, a.EcosystemSpecific)
				if affected {
					filteredAffected = append(filteredAffected, a)
				}
			}
			if len(filteredAffected) == 0 {
				continue
			}
			// save the non-empty vulnerability with only
			// affected symbols.
			newV := *v
			newV.Affected = filteredAffected
			filteredVulns = append(filteredVulns, &newV)
		}
		filteredMod = append(filteredMod, modVulns{
			mod:   module,
			vulns: filteredVulns,
		})
	}
	return filteredMod
}

func matchesPlatform(os, arch string, e osv.EcosystemSpecific) bool {
	matchesOS := len(e.GOOS) == 0
	matchesArch := len(e.GOARCH) == 0
	for _, o := range e.GOOS {
		if os == o {
			matchesOS = true
			break
		}
	}
	for _, a := range e.GOARCH {
		if arch == a {
			matchesArch = true
			break
		}
	}
	return matchesOS && matchesArch
}

// vulnsForPackage returns the vulnerabilities for the module which is the most
// specific prefix of importPath, or nil if there is no matching module with
// vulnerabilities.
func (mv moduleVulnerabilities) vulnsForPackage(importPath string) []*osv.Entry {
	isStd := isStdPackage(importPath)
	var mostSpecificMod *modVulns
	for _, mod := range mv {
		md := mod
		if isStd && mod.mod == stdlibModule {
			// standard library packages do not have an associated module,
			// so we relate them to the artificial stdlib module.
			mostSpecificMod = &md
		} else if strings.HasPrefix(importPath, md.mod.Path) {
			if mostSpecificMod == nil || len(mostSpecificMod.mod.Path) < len(md.mod.Path) {
				mostSpecificMod = &md
			}
		}
	}

	if mostSpecificMod == nil {
		return nil
	}

	if mostSpecificMod.mod.Replace != nil {
		// standard libraries do not have a module nor replace module
		importPath = fmt.Sprintf("%s%s", mostSpecificMod.mod.Replace.Path, strings.TrimPrefix(importPath, mostSpecificMod.mod.Path))
	}
	vulns := mostSpecificMod.vulns
	packageVulns := []*osv.Entry{}
	for _, v := range vulns {
		for _, a := range v.Affected {
			if a.Package.Name == importPath {
				packageVulns = append(packageVulns, v)
				break
			}
		}
	}
	return packageVulns
}

// vulnsForSymbol returns vulnerabilities for `symbol` in `mv.VulnsForPackage(importPath)`.
func (mv moduleVulnerabilities) vulnsForSymbol(importPath, symbol string) []*osv.Entry {
	vulns := mv.vulnsForPackage(importPath)
	if vulns == nil {
		return nil
	}

	symbolVulns := []*osv.Entry{}
	for _, v := range vulns {
	vulnLoop:
		for _, a := range v.Affected {
			if a.Package.Name != importPath {
				continue
			}
			if len(a.EcosystemSpecific.Symbols) == 0 {
				symbolVulns = append(symbolVulns, v)
				continue vulnLoop
			}
			for _, s := range a.EcosystemSpecific.Symbols {
				if s == symbol {
					symbolVulns = append(symbolVulns, v)
					continue vulnLoop
				}
			}
		}
	}
	return symbolVulns
}

func newModuleConverter() func(m *packages.Module) *Module {
	pmap := map[*packages.Module]*Module{}
	var convert func(m *packages.Module) *Module
	convert = func(m *packages.Module) *Module {
		if m == nil {
			return nil
		}
		if vm, ok := pmap[m]; ok {
			return vm
		}
		vm := &Module{
			Path:    m.Path,
			Version: m.Version,
			Dir:     m.Dir,
			Replace: convert(m.Replace),
		}
		pmap[m] = vm
		return vm
	}
	return convert
}
<commit_msg>vulncheck: remove ResultVersion<commit_after>// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package vulncheck

import (
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"strings"

	"golang.org/x/tools/go/packages"
	"golang.org/x/vuln/client"
	"golang.org/x/vuln/osv"
)

// Config is used for configuring vulncheck algorithms.
type Config struct {
	// ImportsOnly instructs vulncheck to analyze import chains only.
	// Otherwise, call chains are analyzed too.
	ImportsOnly bool

	// Client is used for querying data from a vulnerability database.
	Client client.Client

	// SourceGoVersion is Go version used to build Source inputs passed
	// to vulncheck. If not provided, the current underlying Go version
	// is used to detect vulnerabilities in Go standard library.
	SourceGoVersion string
}

// Package is a Go package for vulncheck analysis. It is a version of
// packages.Package trimmed down to reduce memory consumption.
type Package struct {
	Name      string
	PkgPath   string
	Imports   []*Package
	Pkg       *types.Package
	Fset      *token.FileSet
	Syntax    []*ast.File
	TypesInfo *types.Info
	Module    *Module
}

// Module is a Go module for vulncheck analysis.
type Module struct {
	Path    string
	Version string
	Dir     string
	Replace *Module
}

// Convert transforms a slice of packages.Package to
// a slice of corresponding vulncheck.Package.
func Convert(pkgs []*packages.Package) []*Package {
	convertMod := newModuleConverter()
	ps := make(map[*packages.Package]*Package)
	var pkg func(*packages.Package) *Package
	pkg = func(p *packages.Package) *Package {
		if vp, ok := ps[p]; ok {
			return vp
		}

		vp := &Package{
			Name:      p.Name,
			PkgPath:   p.PkgPath,
			Pkg:       p.Types,
			Fset:      p.Fset,
			Syntax:    p.Syntax,
			TypesInfo: p.TypesInfo,
			Module:    convertMod(p.Module),
		}
		ps[p] = vp

		for _, i := range p.Imports {
			vp.Imports = append(vp.Imports, pkg(i))
		}
		return vp
	}

	var vpkgs []*Package
	for _, p := range pkgs {
		vpkgs = append(vpkgs, pkg(p))
	}
	return vpkgs
}

// Result contains information on how known vulnerabilities are reachable
// in the call graph, package imports graph, and module requires graph of
// the user code.
type Result struct {
	// Calls is a call graph whose roots are program entry functions and
	// methods, and sinks are known vulnerable symbols. It is empty when
	// Config.ImportsOnly is true or when no vulnerable symbols are reachable
	// via the program call graph.
	Calls *CallGraph

	// Imports is a package dependency graph whose roots are entry user packages
	// and sinks are packages with some known vulnerable symbols. It is empty
	// when no packages with vulnerabilities are imported in the program.
	Imports *ImportGraph

	// Requires is a module dependency graph whose roots are entry user modules
	// and sinks are modules with some vulnerable packages. It is empty when no
	// modules with vulnerabilities are required by the program. If used, the
	// standard library is modeled as an artificial "stdlib" module whose version
	// is the Go version used to build the code under analysis.
	Requires *RequireGraph

	// Vulns contains information on detected vulnerabilities and their place in
	// the above graphs. Only vulnerabilities whose symbols are reachable in Calls,
	// or whose packages are imported in Imports, or whose modules are required in
	// Requires, have an entry in Vulns.
	Vulns []*Vuln

	// Modules are the modules that comprise the user code.
	Modules []*Module
}

// Vuln provides information on how a vulnerability is affecting user code by
// connecting it to the Result.{Calls,Imports,Requires} graphs. Vulnerabilities
// detected in Go binaries do not appear in the Result graphs.
type Vuln struct {
	// OSV contains information on the detected vulnerability in the shared
	// vulnerability format.
	//
	// OSV, Symbol, PkgPath, and ModPath identify a vulnerability.
	//
	// Note that *osv.Entry may describe multiple symbols from multiple
	// packages.
	OSV *osv.Entry

	// Symbol is the name of the detected vulnerable function or method.
	Symbol string

	// PkgPath is the package path of the detected Symbol.
	PkgPath string

	// ModPath is the module path corresponding to PkgPath.
	ModPath string

	// CallSink is the ID of the FuncNode in Result.Calls corresponding to
	// Symbol.
	//
	// When analyzing binaries, Symbol is not reachable, or Config.ImportsOnly
	// is true, CallSink will be unavailable and set to 0.
	CallSink int

	// ImportSink is the ID of the PkgNode in Result.Imports corresponding to
	// PkgPath.
	//
	// When analyzing binaries or PkgPath is not imported, ImportSink will be
	// unavailable and set to 0.
	ImportSink int

	// RequireSink is the ID of the ModNode in Result.Requires corresponding to
	// ModPath.
	//
	// When analyzing binaries, RequireSink will be unavailable and set to 0.
	RequireSink int
}

// CallGraph is a slice of a full program call graph whose sinks are vulnerable
// functions and sources are entry points of user packages.
//
// CallGraph is directed from vulnerable functions towards program entry
// functions (see FuncNode) for a more efficient traversal of the slice
// related to a particular vulnerability.
type CallGraph struct {
	// Functions contains all call graph nodes as a map: FuncNode.ID -> FuncNode.
	Functions map[int]*FuncNode

	// Entries are IDs of a subset of Functions representing vulncheck entry points.
	Entries []int
}

// A FuncNode describes a function in the call graph.
type FuncNode struct {
	// ID is the id used to identify the FuncNode in CallGraph.
	ID int

	// Name is the name of the function.
	Name string

	// RecvType is the receiver object type of this function, if any.
	RecvType string

	// PkgPath is the import path of the package containing the function.
	PkgPath string

	// Position describes the position of the function in the file.
	Pos *token.Position

	// CallSites is a set of call sites where this function is called.
	CallSites []*CallSite
}

func (fn *FuncNode) String() string {
	if fn.RecvType == "" {
		return fmt.Sprintf("%s.%s", fn.PkgPath, fn.Name)
	}
	return fmt.Sprintf("%s.%s", fn.RecvType, fn.Name)
}

// A CallSite describes a function call.
type CallSite struct {
	// Parent is ID of the enclosing function where the call is made.
	Parent int

	// Name stands for the name of the function (variable) being called.
	Name string

	// RecvType is the full path of the receiver object type, if any.
	RecvType string

	// Position describes the position of the function in the file.
	Pos *token.Position

	// Resolved indicates if the called function can be statically resolved.
	Resolved bool
}

// RequireGraph is a slice of a full program module requires graph whose sinks
// are modules with known vulnerabilities and sources are modules of user entry
// packages.
//
// RequireGraph is directed from a vulnerable module towards the program entry
// modules (see ModNode) for a more efficient traversal of the slice related
// to a particular vulnerability.
type RequireGraph struct {
	// Modules contains all module nodes as a map: module node id -> module node.
	Modules map[int]*ModNode

	// Entries are IDs of a subset of Modules representing modules of vulncheck entry points.
	Entries []int
}

// A ModNode describes a module in the requires graph.
type ModNode struct {
	// ID is the id used to identify the ModNode in CallGraph.
	ID int

	// Path is the module path.
	Path string

	// Version is the module version.
	Version string

	// Replace is the ID of the replacement module node.
	// A zero value means there is no replacement.
	Replace int

	// RequiredBy contains IDs of the modules requiring this module.
	RequiredBy []int
}

// ImportGraph is a slice of a full program package import graph whose sinks are
// packages with some known vulnerabilities and sources are user specified
// packages.
//
// ImportGraph is directed from a vulnerable package towards the program entry
// packages (see PkgNode) for a more efficient traversal of the slice related
// to a particular vulnerability.
type ImportGraph struct {
	// Packages contains all package nodes as a map: package node id -> package node.
	Packages map[int]*PkgNode

	// Entries are IDs of a subset of Packages representing packages of vulncheck entry points.
	Entries []int
}

// A PkgNode describes a package in the import graph.
type PkgNode struct {
	// ID is the id used to identify the PkgNode in ImportGraph.
	ID int

	// Name is the package identifier as it appears in the source code.
	Name string

	// Path is the package path.
	Path string

	// Module holds ID of the corresponding module (node) in the Requires graph.
	Module int

	// ImportedBy contains IDs of packages directly importing this package.
	ImportedBy []int

	// pkg is used for connecting package node to module and call graph nodes.
	pkg *Package
}

// moduleVulnerabilities is an internal structure for
// holding and querying vulnerabilities provided by a
// vulnerability database client.
type moduleVulnerabilities []modVulns

// modVulns groups vulnerabilities per module.
type modVulns struct {
	mod   *Module
	vulns []*osv.Entry
}

func (mv moduleVulnerabilities) filter(os, arch string) moduleVulnerabilities {
	var filteredMod moduleVulnerabilities
	for _, mod := range mv {
		module := mod.mod
		modVersion := module.Version
		if module.Replace != nil {
			modVersion = module.Replace.Version
		}
		// TODO(https://golang.org/issues/49264): if modVersion == "", try vcs?
		var filteredVulns []*osv.Entry
		for _, v := range mod.vulns {
			var filteredAffected []osv.Affected
			for _, a := range v.Affected {
				// A module version is affected if
				//  - it is included in one of the affected version ranges
				//  - and module version is not ""
				//  The latter means the module version is not available, so
				//  we don't want to spam users with potential false alarms.
				//  TODO: issue warning for "" cases above?
				affected := modVersion != "" && a.Ranges.AffectsSemver(modVersion) && matchesPlatform(os, arch, a.EcosystemSpecific)
				if affected {
					filteredAffected = append(filteredAffected, a)
				}
			}
			if len(filteredAffected) == 0 {
				continue
			}
			// save the non-empty vulnerability with only
			// affected symbols.
			newV := *v
			newV.Affected = filteredAffected
			filteredVulns = append(filteredVulns, &newV)
		}
		filteredMod = append(filteredMod, modVulns{
			mod:   module,
			vulns: filteredVulns,
		})
	}
	return filteredMod
}

func matchesPlatform(os, arch string, e osv.EcosystemSpecific) bool {
	matchesOS := len(e.GOOS) == 0
	matchesArch := len(e.GOARCH) == 0
	for _, o := range e.GOOS {
		if os == o {
			matchesOS = true
			break
		}
	}
	for _, a := range e.GOARCH {
		if arch == a {
			matchesArch = true
			break
		}
	}
	return matchesOS && matchesArch
}

// vulnsForPackage returns the vulnerabilities for the module which is the most
// specific prefix of importPath, or nil if there is no matching module with
// vulnerabilities.
func (mv moduleVulnerabilities) vulnsForPackage(importPath string) []*osv.Entry {
	isStd := isStdPackage(importPath)
	var mostSpecificMod *modVulns
	for _, mod := range mv {
		md := mod
		if isStd && mod.mod == stdlibModule {
			// standard library packages do not have an associated module,
			// so we relate them to the artificial stdlib module.
			mostSpecificMod = &md
		} else if strings.HasPrefix(importPath, md.mod.Path) {
			if mostSpecificMod == nil || len(mostSpecificMod.mod.Path) < len(md.mod.Path) {
				mostSpecificMod = &md
			}
		}
	}

	if mostSpecificMod == nil {
		return nil
	}

	if mostSpecificMod.mod.Replace != nil {
		// standard libraries do not have a module nor replace module
		importPath = fmt.Sprintf("%s%s", mostSpecificMod.mod.Replace.Path, strings.TrimPrefix(importPath, mostSpecificMod.mod.Path))
	}
	vulns := mostSpecificMod.vulns
	packageVulns := []*osv.Entry{}
	for _, v := range vulns {
		for _, a := range v.Affected {
			if a.Package.Name == importPath {
				packageVulns = append(packageVulns, v)
				break
			}
		}
	}
	return packageVulns
}

// vulnsForSymbol returns vulnerabilities for `symbol` in `mv.VulnsForPackage(importPath)`.
func (mv moduleVulnerabilities) vulnsForSymbol(importPath, symbol string) []*osv.Entry {
	vulns := mv.vulnsForPackage(importPath)
	if vulns == nil {
		return nil
	}

	symbolVulns := []*osv.Entry{}
	for _, v := range vulns {
	vulnLoop:
		for _, a := range v.Affected {
			if a.Package.Name != importPath {
				continue
			}
			if len(a.EcosystemSpecific.Symbols) == 0 {
				symbolVulns = append(symbolVulns, v)
				continue vulnLoop
			}
			for _, s := range a.EcosystemSpecific.Symbols {
				if s == symbol {
					symbolVulns = append(symbolVulns, v)
					continue vulnLoop
				}
			}
		}
	}
	return symbolVulns
}

func newModuleConverter() func(m *packages.Module) *Module {
	pmap := map[*packages.Module]*Module{}
	var convert func(m *packages.Module) *Module
	convert = func(m *packages.Module) *Module {
		if m == nil {
			return nil
		}
		if vm, ok := pmap[m]; ok {
			return vm
		}
		vm := &Module{
			Path:    m.Path,
			Version: m.Version,
			Dir:     m.Dir,
			Replace: convert(m.Replace),
		}
		pmap[m] = vm
		return vm
	}
	return convert
}
<|endoftext|>


<commit_before><commit_msg>removed creating mkcert localhost<commit_after><|endoftext|>


<commit_before>package couchdb2_goclient

type Database interface {
	Exists(string) (*bool, error)
	Meta(string) (*DbMetaResponse, error)
	CreateDb(string) (*OkKoResponse, error)
	DeleteDb(string) (*OkKoResponse, error)
	CreateDocument(db string, doc interface{})
	CreateDocumentExtra(db string, doc interface{}, batch bool, fullCommit bool)
	Documents(db string, req *AllDocsRequest) (*AllDocsResponse, error)
	DocumentsWithIDs(db string, req *DocsWithIDsRequest) (*AllDocsResponse, error)
	Bulk(db string, docs []interface{}, newEdits bool) (*BulkResponse, error)
	Find(db string, req *FindRequest) (*FindResponse, error)
	SetIndex(db string, req *SetIndexRequest) (*SetIndexResponse, error)
	Index(db string) (*IndexResponse, error)
	Delete(db string, designDoc string, name string) (*OkKoResponse, error)
	Explain(db string, req *FindRequest) (*ExplainResponse, error)
	Changes(db string, req map[string]string) (*ChangesResponse, error)
	//ChangesContinuous(db string, queryReq map[string]string, inCh chan *DbResult, quitCh chan struct{}) (chan *DbResult, chan<- struct{}, error)
	ChangesContinuousRaw(db string, queryReq map[string]string, inCh chan *DbResult, quitCh chan struct{}) (chan *DbResult, chan<- struct{}, error)
	Compact(db string) (*OkKoResponse, error)
	CompactDesignDoc(db string, ddoc string) (*OkKoResponse, error)
	EnsureFullCommit(db string) (*EnsureFullCommitResponse, error)
	ViewCleanup(db string) (*OkKoResponse, error)
	Security(db string) (*SecurityResponse, error)
	SetSecurity(db string, req *SecurityRequest) (*OkKoResponse, error)
	DoPurge(db string, req map[string]interface{}) (*DoPurgeResponse, error)
	MissingKeys(db string, req map[string]interface{}) (*MissingKeysResponse, error)
	RevsDiff(db string, req *RevsDiffRequest) (*RevsDiffResponse, error)
	RevsLimit(db string) (int, error)
	SetRevsLimit(db string, n int) (*OkKoResponse, error)
}

type DbMetaResponse struct {
	ErrorResponse
	CommittedUpdateSeq int    `json:"committed_update_seq"`
	CompactRunning     bool   `json:"compact_running"`
	DataSize           int    `json:"data_size"`
	DbName             string `json:"db_name"`
	DiskFormatVersion  int    `json:"disk_format_version"`
	DiskSize           int    `json:"disk_size"`
	DocCount           int    `json:"doc_count"`
	DocDelCount        int    `json:"doc_del_count"`
	InstanceStartTime  string `json:"instance_start_time"`
	PurgeSeq           int    `json:"purge_seq"`
	UpdateSeq          int    `json:"update_seq"`
}

type OkKoResponse struct {
	ErrorResponse
	Ok bool `json:"ok"`
}

type CreateDocumentResponse struct {
	ErrorResponse
	ID  string `json:"id"`
	Ok  bool   `json:"ok"`
	Rev string `json:"rev, omitempty"`
}

type AllDocsRequest struct {
	Conflicts        bool   `json:"conflicts, omitempty"`
	Descending       bool   `json:"descending, omitempty"`
	EndKey           string `json:"endkey, omitempty"`
	End_key          string `json:"end_key, omitempty"`
	EndKey_DocID     string `json:"endkey_docid, omitempty"`
	End_Key_Doc_ID   string `json:"end_key_doc_id, omitempty"`
	IncludeDocs      bool   `json:"include_docs, omitempty"`
	InclusiveEnd     bool   `json:"inclusive_end, omitempty"`
	Key              string `json:"key, omitempty"`
	Keys             string `json:"keys, omitempty"`
	Limit            int    `json:"limit, omitempty"`
	Skip             int    `json:"skip, omitempty"`
	Stale            string `json:"stale, omitempty"`
	StartKey         string `json:"startkey, omitempty"`
	Start_Key        string `json:"start_key, omitempty"`
	StartKey_DocID   string `json:"startkey_docid, omitempty"`
	Start_Key_Doc_ID string `json:"start_key_doc_id, omitempty"`
	UpdateSeq        bool   `json:"update_seq, omitempty"`
}

type AllDocsResponse struct {
	ErrorResponse
	Offset int `json:"offset"`
	Rows   []struct {
		ID    string `json:"id"`
		Key   string `json:"key"`
		Value struct {
			Rev string `json:"rev"`
		} `json:"value"`
	} `json:"rows"`
	TotalRows int `json:"total_rows"`
}

type DocsWithIDsRequest struct {
	Keys []string `json:"keys"`
}

type BulkResponse []CreateDocumentResponse

type FindRequest struct {
	Selector map[string]interface{} `json:"selector"`
	Fields   []string               `json:"fields"`
	Sort     []struct {
		Year string `json:"year"`
	} `json:"sort"`
	Limit int `json:"limit"`
	Skip  int `json:"skip"`
}

type FindResponse struct {
	ErrorResponse
	Docs []map[string]interface{} `json:"docs"`
}

type SetIndexRequest struct {
	Index map[string]interface{} `json:"index"`
	Ddoc  string                 `json:"ddocs"`
	Name  string                 `json:"name"`
}

type SetIndexResponse struct {
	ErrorResponse
	Result string `json:"result"`
	ID     string `json:"id"`
	Name   string `json:"name"`
}

type IndexResponse struct {
	ErrorResponse
	TotalRows int `json:"total_rows"`
	Indexes   []struct {
		Ddoc interface{} `json:"ddoc"`
		Name string      `json:"name"`
		Type string      `json:"type"`
		Def  struct {
			Fields []struct {
				ID string `json:"_id"`
			} `json:"fields"`
		} `json:"def"`
	} `json:"indexes"`
}

type ExplainResponse struct {
	ErrorResponse
	Dbname string `json:"dbname"`
	Index  struct {
		Ddoc string `json:"ddoc"`
		Name string `json:"name"`
		Type string `json:"type"`
		Def  struct {
			Fields []struct {
				Year string `json:"year"`
			} `json:"fields"`
		} `json:"def"`
	} `json:"index"`
	Selector struct {
		Year struct {
			Gt int `json:"$gt"`
		} `json:"year"`
	} `json:"selector"`
	Opts struct {
		UseIndex []interface{} `json:"use_index"`
		Bookmark string        `json:"bookmark"`
		Limit    int           `json:"limit"`
		Skip     int           `json:"skip"`
		Sort     struct {
		} `json:"sort"`
		Fields    []string `json:"fields"`
		R         []int    `json:"r"`
		Conflicts bool     `json:"conflicts"`
	} `json:"opts"`
	Limit  int      `json:"limit"`
	Skip   int      `json:"skip"`
	Fields []string `json:"fields"`
	Range  struct {
		StartKey []int `json:"start_key"`
		EndKey   []struct {
		} `json:"end_key"`
	} `json:"range"`
}

type ChangesRequest struct {
	DocsIds         []string `json:"docs_ids"`
	Conflicts       bool     `json:"conflicts"`
	Descending      bool     `json:"descending"`
	Feed            string   `json:"feed"`
	Filter          string   `json:"filter"`
	HeartBeat       int      `json:"heartbeat"`
	IncludeDocs     bool     `json:"include_docs"`
	Attachments     bool     `json:"attachments"`
	AttEncodingInfo bool     `json:"att_encoding_info"`
	LastEventId     int      `json:"last-event-id"`
	Limit           int      `json:"limit"`
	Since           int      `json:"since"`
	Style           string   `json:"string"`
	Timeout         int      `json:"timeout"`
	View            string   `json:"view"`
}

type LastSeq struct {
	Last_Seq *int `json:"last_seq"`
}

type DbResult struct {
	LastSeq
	*ErrorResponse
	Changes []struct {
		Rev string `json:"rev"`
	} `json:"changes"`
	ID      string                 `json:"id"`
	Seq     string                 `json:"seq"`
	Deleted bool                   `json:"deleted,omitempty"`
	DbName  string                 `json:"database,omitempty"`
	Doc     map[string]interface{} `json:"doc,omitempty"`
}

type Deleted struct {
	Deleted bool   `json:"_deleted"`
	Id      string `json:"_id"`
	Rev     string `json:"_rev"`
}

type ChangesResponse struct {
	ErrorResponse
	LastSeq int         `json:"last_seq"`
	Results []*DbResult `json:"results"`
}

type EnsureFullCommitResponse struct {
	OkKoResponse
	InstanceStartTime string `json:"instance_start_time"`
}

type SecurityRequest struct {
	SecurityResponse
}

type SecurityResponse struct {
	ErrorResponse
	Admins struct {
		Names []string `json:"names"`
		Roles []string `json:"roles"`
	} `json:"admins"`
	Members struct {
		Names []string `json:"names"`
		Roles []string `json:"roles"`
	} `json:"members"`
}

type DoPurgeResponse struct {
	ErrorResponse
	PurgeSeq int `json:"purge_seq"`
	Purged   struct {
		C6114C65E295552Ab1019E2B046B10E []string `json:"c6114c65e295552ab1019e2b046b10e"`
	} `json:"purged"`
}

type MissingKeysResponse struct {
	ErrorResponse
	MissedRevs []map[string]interface{} `json:"missed_revs"`
}

type RevsDiffRequest map[string][]string

type RevsDiffResponse map[string]struct {
	ErrorResponse
	Missing           []string `json:"missing"`
	PossibleAncestors []string `json:"possible_ancestors"`
}
<commit_msg>Updated sequence id to use an interface so it works with both versions of Couchdb<commit_after>package couchdb2_goclient

type Database interface {
	Exists(string) (*bool, error)
	Meta(string) (*DbMetaResponse, error)
	CreateDb(string) (*OkKoResponse, error)
	DeleteDb(string) (*OkKoResponse, error)
	CreateDocument(db string, doc interface{})
	CreateDocumentExtra(db string, doc interface{}, batch bool, fullCommit bool)
	Documents(db string, req *AllDocsRequest) (*AllDocsResponse, error)
	DocumentsWithIDs(db string, req *DocsWithIDsRequest) (*AllDocsResponse, error)
	Bulk(db string, docs []interface{}, newEdits bool) (*BulkResponse, error)
	Find(db string, req *FindRequest) (*FindResponse, error)
	SetIndex(db string, req *SetIndexRequest) (*SetIndexResponse, error)
	Index(db string) (*IndexResponse, error)
	Delete(db string, designDoc string, name string) (*OkKoResponse, error)
	Explain(db string, req *FindRequest) (*ExplainResponse, error)
	Changes(db string, req map[string]string) (*ChangesResponse, error)
	//ChangesContinuous(db string, queryReq map[string]string, inCh chan *DbResult, quitCh chan struct{}) (chan *DbResult, chan<- struct{}, error)
	ChangesContinuousRaw(db string, queryReq map[string]string, inCh chan *DbResult, quitCh chan struct{}) (chan *DbResult, chan<- struct{}, error)
	Compact(db string) (*OkKoResponse, error)
	CompactDesignDoc(db string, ddoc string) (*OkKoResponse, error)
	EnsureFullCommit(db string) (*EnsureFullCommitResponse, error)
	ViewCleanup(db string) (*OkKoResponse, error)
	Security(db string) (*SecurityResponse, error)
	SetSecurity(db string, req *SecurityRequest) (*OkKoResponse, error)
	DoPurge(db string, req map[string]interface{}) (*DoPurgeResponse, error)
	MissingKeys(db string, req map[string]interface{}) (*MissingKeysResponse, error)
	RevsDiff(db string, req *RevsDiffRequest) (*RevsDiffResponse, error)
	RevsLimit(db string) (int, error)
	SetRevsLimit(db string, n int) (*OkKoResponse, error)
}

type DbMetaResponse struct {
	ErrorResponse
	CommittedUpdateSeq int    `json:"committed_update_seq"`
	CompactRunning     bool   `json:"compact_running"`
	DataSize           int    `json:"data_size"`
	DbName             string `json:"db_name"`
	DiskFormatVersion  int    `json:"disk_format_version"`
	DiskSize           int    `json:"disk_size"`
	DocCount           int    `json:"doc_count"`
	DocDelCount        int    `json:"doc_del_count"`
	InstanceStartTime  string `json:"instance_start_time"`
	PurgeSeq           int    `json:"purge_seq"`
	UpdateSeq          int    `json:"update_seq"`
}

type OkKoResponse struct {
	ErrorResponse
	Ok bool `json:"ok"`
}

type CreateDocumentResponse struct {
	ErrorResponse
	ID  string `json:"id"`
	Ok  bool   `json:"ok"`
	Rev string `json:"rev, omitempty"`
}

type AllDocsRequest struct {
	Conflicts        bool   `json:"conflicts, omitempty"`
	Descending       bool   `json:"descending, omitempty"`
	EndKey           string `json:"endkey, omitempty"`
	End_key          string `json:"end_key, omitempty"`
	EndKey_DocID     string `json:"endkey_docid, omitempty"`
	End_Key_Doc_ID   string `json:"end_key_doc_id, omitempty"`
	IncludeDocs      bool   `json:"include_docs, omitempty"`
	InclusiveEnd     bool   `json:"inclusive_end, omitempty"`
	Key              string `json:"key, omitempty"`
	Keys             string `json:"keys, omitempty"`
	Limit            int    `json:"limit, omitempty"`
	Skip             int    `json:"skip, omitempty"`
	Stale            string `json:"stale, omitempty"`
	StartKey         string `json:"startkey, omitempty"`
	Start_Key        string `json:"start_key, omitempty"`
	StartKey_DocID   string `json:"startkey_docid, omitempty"`
	Start_Key_Doc_ID string `json:"start_key_doc_id, omitempty"`
	UpdateSeq        bool   `json:"update_seq, omitempty"`
}

type AllDocsResponse struct {
	ErrorResponse
	Offset int `json:"offset"`
	Rows   []struct {
		ID    string `json:"id"`
		Key   string `json:"key"`
		Value struct {
			Rev string `json:"rev"`
		} `json:"value"`
	} `json:"rows"`
	TotalRows int `json:"total_rows"`
}

type DocsWithIDsRequest struct {
	Keys []string `json:"keys"`
}

type BulkResponse []CreateDocumentResponse

type FindRequest struct {
	Selector map[string]interface{} `json:"selector"`
	Fields   []string               `json:"fields"`
	Sort     []struct {
		Year string `json:"year"`
	} `json:"sort"`
	Limit int `json:"limit"`
	Skip  int `json:"skip"`
}

type FindResponse struct {
	ErrorResponse
	Docs []map[string]interface{} `json:"docs"`
}

type SetIndexRequest struct {
	Index map[string]interface{} `json:"index"`
	Ddoc  string                 `json:"ddocs"`
	Name  string                 `json:"name"`
}

type SetIndexResponse struct {
	ErrorResponse
	Result string `json:"result"`
	ID     string `json:"id"`
	Name   string `json:"name"`
}

type IndexResponse struct {
	ErrorResponse
	TotalRows int `json:"total_rows"`
	Indexes   []struct {
		Ddoc interface{} `json:"ddoc"`
		Name string      `json:"name"`
		Type string      `json:"type"`
		Def  struct {
			Fields []struct {
				ID string `json:"_id"`
			} `json:"fields"`
		} `json:"def"`
	} `json:"indexes"`
}

type ExplainResponse struct {
	ErrorResponse
	Dbname string `json:"dbname"`
	Index  struct {
		Ddoc string `json:"ddoc"`
		Name string `json:"name"`
		Type string `json:"type"`
		Def  struct {
			Fields []struct {
				Year string `json:"year"`
			} `json:"fields"`
		} `json:"def"`
	} `json:"index"`
	Selector struct {
		Year struct {
			Gt int `json:"$gt"`
		} `json:"year"`
	} `json:"selector"`
	Opts struct {
		UseIndex []interface{} `json:"use_index"`
		Bookmark string        `json:"bookmark"`
		Limit    int           `json:"limit"`
		Skip     int           `json:"skip"`
		Sort     struct {
		} `json:"sort"`
		Fields    []string `json:"fields"`
		R         []int    `json:"r"`
		Conflicts bool     `json:"conflicts"`
	} `json:"opts"`
	Limit  int      `json:"limit"`
	Skip   int      `json:"skip"`
	Fields []string `json:"fields"`
	Range  struct {
		StartKey []int `json:"start_key"`
		EndKey   []struct {
		} `json:"end_key"`
	} `json:"range"`
}

type ChangesRequest struct {
	DocsIds         []string `json:"docs_ids"`
	Conflicts       bool     `json:"conflicts"`
	Descending      bool     `json:"descending"`
	Feed            string   `json:"feed"`
	Filter          string   `json:"filter"`
	HeartBeat       int      `json:"heartbeat"`
	IncludeDocs     bool     `json:"include_docs"`
	Attachments     bool     `json:"attachments"`
	AttEncodingInfo bool     `json:"att_encoding_info"`
	LastEventId     int      `json:"last-event-id"`
	Limit           int      `json:"limit"`
	Since           int      `json:"since"`
	Style           string   `json:"string"`
	Timeout         int      `json:"timeout"`
	View            string   `json:"view"`
}

type LastSeq struct {
	Last_Seq *int `json:"last_seq"`
}

type DbResult struct {
	LastSeq
	*ErrorResponse
	Changes []struct {
		Rev string `json:"rev"`
	} `json:"changes"`
	ID      string                 `json:"id"`
	Seq     interface{}            `json:"seq"`
	Deleted bool                   `json:"deleted,omitempty"`
	DbName  string                 `json:"database,omitempty"`
	Doc     map[string]interface{} `json:"doc,omitempty"`
}

type Deleted struct {
	Deleted bool   `json:"_deleted"`
	Id      string `json:"_id"`
	Rev     string `json:"_rev"`
}

type ChangesResponse struct {
	ErrorResponse
	LastSeq int         `json:"last_seq"`
	Results []*DbResult `json:"results"`
}

type EnsureFullCommitResponse struct {
	OkKoResponse
	InstanceStartTime string `json:"instance_start_time"`
}

type SecurityRequest struct {
	SecurityResponse
}

type SecurityResponse struct {
	ErrorResponse
	Admins struct {
		Names []string `json:"names"`
		Roles []string `json:"roles"`
	} `json:"admins"`
	Members struct {
		Names []string `json:"names"`
		Roles []string `json:"roles"`
	} `json:"members"`
}

type DoPurgeResponse struct {
	ErrorResponse
	PurgeSeq int `json:"purge_seq"`
	Purged   struct {
		C6114C65E295552Ab1019E2B046B10E []string `json:"c6114c65e295552ab1019e2b046b10e"`
	} `json:"purged"`
}

type MissingKeysResponse struct {
	ErrorResponse
	MissedRevs []map[string]interface{} `json:"missed_revs"`
}

type RevsDiffRequest map[string][]string

type RevsDiffResponse map[string]struct {
	ErrorResponse
	Missing           []string `json:"missing"`
	PossibleAncestors []string `json:"possible_ancestors"`
}
<|endoftext|>


<commit_before>// Copyright 2019 fatedier, fatedier@gmail.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package plugin

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"reflect"
)

type HTTPPluginOptions struct {
	Name string
	Addr string
	Path string
	Ops  []string
}

type httpPlugin struct {
	options HTTPPluginOptions

	url    string
	client *http.Client
}

func NewHTTPPluginOptions(options HTTPPluginOptions) Plugin {
	return &httpPlugin{
		options: options,
		url:     fmt.Sprintf("http://%s%s", options.Addr, options.Path),
		client:  &http.Client{},
	}
}

func (p *httpPlugin) Name() string {
	return p.options.Name
}

func (p *httpPlugin) IsSupport(op string) bool {
	for _, v := range p.options.Ops {
		if v == op {
			return true
		}
	}
	return false
}

func (p *httpPlugin) Handle(ctx context.Context, op string, content interface{}) (*Response, interface{}, error) {
	r := &Request{
		Version: APIVersion,
		Op:      op,
		Content: content,
	}
	var res Response
	res.Content = reflect.New(reflect.TypeOf(content)).Interface()
	if err := p.do(ctx, r, &res); err != nil {
		return nil, nil, err
	}
	return &res, res.Content, nil
}

func (p *httpPlugin) do(ctx context.Context, r *Request, res *Response) error {
	buf, err := json.Marshal(r)
	if err != nil {
		return err
	}
	req, err := http.NewRequest("POST", p.url, bytes.NewReader(buf))
	if err != nil {
		return err
	}
	req = req.WithContext(ctx)
	req.Header.Set("X-Frp-Reqid", GetReqidFromContext(ctx))
	resp, err := p.client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("do http request error code: %d", resp.StatusCode)
	}
	buf, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	if err = json.Unmarshal(buf, res); err != nil {
		return err
	}
	return nil
}
<commit_msg>fix: send server plugin request as json (#1690)<commit_after>// Copyright 2019 fatedier, fatedier@gmail.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package plugin

import (
	"bytes"
	"context"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"reflect"
)

type HTTPPluginOptions struct {
	Name string
	Addr string
	Path string
	Ops  []string
}

type httpPlugin struct {
	options HTTPPluginOptions

	url    string
	client *http.Client
}

func NewHTTPPluginOptions(options HTTPPluginOptions) Plugin {
	return &httpPlugin{
		options: options,
		url:     fmt.Sprintf("http://%s%s", options.Addr, options.Path),
		client:  &http.Client{},
	}
}

func (p *httpPlugin) Name() string {
	return p.options.Name
}

func (p *httpPlugin) IsSupport(op string) bool {
	for _, v := range p.options.Ops {
		if v == op {
			return true
		}
	}
	return false
}

func (p *httpPlugin) Handle(ctx context.Context, op string, content interface{}) (*Response, interface{}, error) {
	r := &Request{
		Version: APIVersion,
		Op:      op,
		Content: content,
	}
	var res Response
	res.Content = reflect.New(reflect.TypeOf(content)).Interface()
	if err := p.do(ctx, r, &res); err != nil {
		return nil, nil, err
	}
	return &res, res.Content, nil
}

func (p *httpPlugin) do(ctx context.Context, r *Request, res *Response) error {
	buf, err := json.Marshal(r)
	if err != nil {
		return err
	}
	req, err := http.NewRequest("POST", p.url, bytes.NewReader(buf))
	if err != nil {
		return err
	}
	req = req.WithContext(ctx)
	req.Header.Set("X-Frp-Reqid", GetReqidFromContext(ctx))
	req.Header.Set("Content-Type", "application/json")
	resp, err := p.client.Do(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("do http request error code: %d", resp.StatusCode)
	}
	buf, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	if err = json.Unmarshal(buf, res); err != nil {
		return err
	}
	return nil
}
<|endoftext|>


<commit_before>package PLUS_test

import (
	. "plus"
	packet "plus/packet"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Plus", func() {
	Context("ConnectionManager", func() {
		It("Deals with new basic packets", func() {
			p := packet.NewBasicPLUSPacket(false, false, false, 1234, 11, 12, []byte{0x00})
			packetConn := NewMockPacketConn()
			packetConn.PutData(p.Buffer())
			manager := NewConnectionManager(packetConn)
			packet, addr, err := manager.ReadPacket()
			Expect(err).ToNot(HaveOccurred())
			Expect(packet).ToNot(Equal(nil))
			Expect(addr).ToNot(Equal(nil))

			conn, feedbackData, err := manager.ProcessPacket(p, addr)
			Expect(err).ToNot(HaveOccurred())
			Expect(conn).ToNot(Equal(nil))
			Expect(conn.CAT()).To(Equal(uint64(1234)))
			Expect(conn.PSE()).To(Equal(uint32(11)))

			var nilbuf []byte
			Expect(feedbackData).To(Equal(nilbuf))
		})

		It("Deals with new extended packets", func() {
			p, err := packet.NewExtendedPLUSPacket(false, false, false, 1234, 11, 12, 0x00, 0x00, []byte{0xCA,0xFE}, []byte{0xBA, 0xBE})

			Expect(err).ToNot(HaveOccurred())

			packetConn := NewMockPacketConn()
			packetConn.PutData(p.Buffer())
			manager := NewConnectionManager(packetConn)
			packet, addr, err := manager.ReadPacket()
			Expect(err).ToNot(HaveOccurred())
			Expect(packet).ToNot(Equal(nil))
			Expect(addr).ToNot(Equal(nil))

			conn, feedbackData, err := manager.ProcessPacket(p, addr)
			Expect(err).ToNot(HaveOccurred())
			Expect(conn).ToNot(Equal(nil))
			Expect(conn.CAT()).To(Equal(uint64(1234)))
			Expect(conn.PSE()).To(Equal(uint32(11)))

			Expect(feedbackData).To(Equal(p.Header()))
		})
	})
})
<commit_msg>+ more tests<commit_after>package PLUS_test

import (
	. "plus"
	packet "plus/packet"

	. "github.com/onsi/ginkgo"
	. "github.com/onsi/gomega"
)

var _ = Describe("Plus", func() {
	Context("ConnectionManager", func() {
		It("Deals with new basic packets", func() {
			p := packet.NewBasicPLUSPacket(false, false, false, 1234, 11, 12, []byte{0x00})
			packetConn := NewMockPacketConn()
			packetConn.PutData(p.Buffer())
			manager := NewConnectionManager(packetConn)
			packet, addr, err := manager.ReadPacket()
			Expect(err).ToNot(HaveOccurred())
			Expect(packet).ToNot(Equal(nil))
			Expect(addr).ToNot(Equal(nil))

			conn, feedbackData, err := manager.ProcessPacket(p, addr)
			Expect(err).ToNot(HaveOccurred())
			Expect(conn).ToNot(Equal(nil))
			Expect(conn.CAT()).To(Equal(uint64(1234)))
			Expect(conn.PSE()).To(Equal(uint32(11)))

			var nilbuf []byte
			Expect(feedbackData).To(Equal(nilbuf))
		})

		It("Deals with new extended packets", func() {
			p, err := packet.NewExtendedPLUSPacket(false, false, false, 1234, 11, 12, 0x01, 0x00, []byte{0xCA,0xFE}, []byte{0xBA, 0xBE})

			Expect(err).ToNot(HaveOccurred())

			packetConn := NewMockPacketConn()
			packetConn.PutData(p.Buffer())
			manager := NewConnectionManager(packetConn)
			packet, addr, err := manager.ReadPacket()
			Expect(err).ToNot(HaveOccurred())
			Expect(packet).ToNot(Equal(nil))
			Expect(addr).ToNot(Equal(nil))

			conn, feedbackData, err := manager.ProcessPacket(p, addr)
			Expect(err).ToNot(HaveOccurred())
			Expect(conn).ToNot(Equal(nil))
			Expect(conn.CAT()).To(Equal(uint64(1234)))
			Expect(conn.PSE()).To(Equal(uint32(11)))

			Expect(feedbackData).To(Equal(p.Header()))
		})

		It("Deals with new extended packets with INTEGRITY_FULL", func() {
			p, err := packet.NewExtendedPLUSPacket(false, false, false, 1234, 11, 12, 0x01, 0x03, []byte{0xCA,0xFE}, []byte{0xBA, 0xBE})

			Expect(err).ToNot(HaveOccurred())

			packetConn := NewMockPacketConn()
			packetConn.PutData(p.Buffer())
			manager := NewConnectionManager(packetConn)
			packet, addr, err := manager.ReadPacket()
			Expect(err).ToNot(HaveOccurred())
			Expect(packet).ToNot(Equal(nil))
			Expect(addr).ToNot(Equal(nil))

			conn, feedbackData, err := manager.ProcessPacket(p, addr)
			Expect(err).ToNot(HaveOccurred())
			Expect(conn).ToNot(Equal(nil))
			Expect(conn.CAT()).To(Equal(uint64(1234)))
			Expect(conn.PSE()).To(Equal(uint32(11)))

			var nilbuf []byte
			Expect(feedbackData).To(Equal(nilbuf))
		})
	})
})
<|endoftext|>


<commit_before>package main

import "os"

func getHouses(s string) (houses int, err error) {
	return
}

func run() int {
	return 0
}

func main() {
	os.Exit(run())
}
<commit_msg>day3 wip<commit_after>package main

import (
	"fmt"
	"os"
)

func getHouses(s string) (houses int, err error) {
	var pos [2]int

	h := make(map[[2]int]bool)

	h[pos] = true

	for _, c := range s {
		switch c {
		case '<':
			pos[0]--
		case '>':
			pos[0]++
		case '^':
			pos[1]++
		case 'v':
			pos[1]--
		default:
			err = fmt.Errorf("invalid character %q", c)
			return
		}
		h[pos] = true
	}

	for k := range h {
		if h[k] {
			houses++
		}
	}
	return
}

func run() int {
	s := ">"
	h, err := getHouses(s)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return 1
	}

	fmt.Printf("houses: %d\n", h)
	return 0
}

func main() {
	os.Exit(run())
}
<|endoftext|>


<commit_before>package followingfeed

import (
	"encoding/json"
	"errors"
	"fmt"
	"koding/tools/logger"
	"socialapi/models"

	verbalexpressions "github.com/VerbalExpressions/GoVerbalExpressions"
	"github.com/jinzhu/gorm"
)

// s := "naber #foo hede #bar dede gel # baz #123 #-`3sdf"
// will find [foo, bar, 123]
// will not find [' baz', '-`3sdf']
// here is the regex -> (?m)(?:#)(\w+)(?: )
var topicRegex = verbalexpressions.New().
	Find("#").
	BeginCapture().
	Word().
	EndCapture().
	Find(" ").
	Regex()

type Action func(*TopicFeedController, *models.ChannelMessage) error

type TopicFeedController struct {
	routes map[string]Action
	log    logger.Log
}

var HandlerNotFoundErr = errors.New("Handler Not Found")

func NewTopicFeedController(log logger.Log) *TopicFeedController {
	// s := "naber #foo hede #bar dede gel # baz #123 #-`3sdf"
	// res := topicRegex.FindAllStringSubmatch(s, -1)
	// fmt.Println("res", res)
	// fmt.Println("res", res[0][1])
	// fmt.Println("res", res[1][1])
	// fmt.Println(topicRegex.String())

	ffc := &TopicFeedController{
		log: log,
	}

	routes := map[string]Action{
		"channel_message_created": (*TopicFeedController).MessageSaved,
		"channel_message_update":  (*TopicFeedController).MessageUpdated,
		"channel_message_deleted": (*TopicFeedController).MessageDeleted,
	}

	ffc.routes = routes

	return ffc
}

func (f *TopicFeedController) HandleEvent(event string, data []byte) error {
	f.log.Debug("New Event Recieved %s", event)
	handler, ok := f.routes[event]
	if !ok {
		return HandlerNotFoundErr
	}

	cm, err := mapMessage(data)
	if err != nil {
		return err
	}

	res, err := isEligible(cm)
	if err != nil {
		return err
	}

	if !res {
		return nil
	}

	return handler(f, cm)
}

func (f *TopicFeedController) MessageSaved(data *models.ChannelMessage) error {

	res := topicRegex.FindAllStringSubmatch(data.Body, -1)
	if len(res) == 0 {
		f.log.Debug("Message doesnt have any topic Body: %s", data.Body)
		return nil
	}

	c, err := fetchChannel(data.InitialChannelId)
	if err != nil {
		return err
	}

	topics := map[string]struct{}{}

	for _, ele := range res {
		topics[ele[1]] = struct{}{}
	}

	for topic := range topics {
		channelName := topic
		tc, err := fetchTopicChannel(c.Group, channelName)
		if err != nil && err != gorm.RecordNotFound {
			return err
		}

		if err == gorm.RecordNotFound {
			tc, err = createTopicChannel(data.AccountId, c.Group, channelName, c.Privacy)
			if err != nil {
				return err
			}
		}

		_, err = tc.AddMessage(data.Id)
		if err != nil {
			return err
		}

	}

	return nil
}

func (f *TopicFeedController) MessageUpdated(data *models.ChannelMessage) error {
	fmt.Println("update", data.InitialChannelId)
	return nil
}

func getTopicDiff(channels []models.Channel, topics []string) map[string][]string {
	res := make(map[string][]string)

	// aggregate all channel names into map
	channelNames := map[string]struct{}{}
	for _, channel := range channels {
		channelNames[channel.Name] = struct{}{}
	}

	// range over new topics, bacause we are gonna remove
	// unused channels
	for _, topic := range topics {
		found := false
		for channelName := range channelNames {
			if channelName == topic {
				found = true
			}
		}
		if !found {
			res["added"] = append(res["added"], topic)
		} else {
			// if we have topic in channels
			// do remove it because at the end we are gonna mark
			// channels as deleted which are still in channelNames
			delete(channelNames, topic)
		}
	}
	// flatten the deleted channel names
	for channelName := range channelNames {
		res["deleted"] = append(res["deleted"], channelName)
	}

	return res
}

func (f *TopicFeedController) MessageDeleted(data *models.ChannelMessage) error {
	cml := models.NewChannelMessageList()
	selector := map[string]interface{}{
		"mesage_id": data.Id,
	}

	if err := cml.DeleteMessagesBySelector(selector); err != nil {
		return err
	}
	return nil
}

func mapMessage(data []byte) (*models.ChannelMessage, error) {
	cm := models.NewChannelMessage()
	if err := json.Unmarshal(data, cm); err != nil {
		return nil, err
	}

	return cm, nil
}

func isEligible(cm *models.ChannelMessage) (bool, error) {
	if cm.InitialChannelId == 0 {
		return false, nil
	}

	if cm.Type != models.ChannelMessage_TYPE_POST {
		return false, nil
	}

	return true, nil
}

// todo add caching here
func fetchChannel(channelId int64) (*models.Channel, error) {
	c := models.NewChannel()
	c.Id = channelId
	// todo - fetch only name here
	if err := c.Fetch(); err != nil {
		return nil, err
	}

	return c, nil
}

// todo add caching here
func fetchTopicChannel(groupName, channelName string) (*models.Channel, error) {
	c := models.NewChannel()

	selector := map[string]interface{}{
		"group": groupName,
		"name":  channelName,
		"type":  models.Channel_TYPE_TOPIC,
	}

	err := c.One(selector)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func createTopicChannel(creatorId int64, groupName, channelName, privacy string) (*models.Channel, error) {
	c := models.NewChannel()
	c.Name = channelName
	c.CreatorId = creatorId
	c.Group = groupName
	c.Purpose = fmt.Sprintf("Channel for %s topic", channelName)
	c.Type = models.Channel_TYPE_TOPIC
	c.Privacy = privacy
	if err := c.Create(); err != nil {
		return nil, err
	}

	return c, nil
}
<commit_msg>Social : delete obsolete channel messages<commit_after>package followingfeed

import (
	"encoding/json"
	"errors"
	"fmt"
	"koding/tools/logger"
	"socialapi/models"

	verbalexpressions "github.com/VerbalExpressions/GoVerbalExpressions"
	"github.com/jinzhu/gorm"
)

// s := "naber #foo hede #bar dede gel # baz #123 #-`3sdf"
// will find [foo, bar, 123]
// will not find [' baz', '-`3sdf']
// here is the regex -> (?m)(?:#)(\w+)(?: )
var topicRegex = verbalexpressions.New().
	Find("#").
	BeginCapture().
	Word().
	EndCapture().
	Find(" ").
	Regex()

type Action func(*TopicFeedController, *models.ChannelMessage) error

type TopicFeedController struct {
	routes map[string]Action
	log    logger.Log
}

var HandlerNotFoundErr = errors.New("Handler Not Found")

func NewTopicFeedController(log logger.Log) *TopicFeedController {
	// s := "naber #foo hede #bar dede gel # baz #123 #-`3sdf"
	// res := topicRegex.FindAllStringSubmatch(s, -1)
	// fmt.Println("res", res)
	// fmt.Println("res", res[0][1])
	// fmt.Println("res", res[1][1])
	// fmt.Println(topicRegex.String())

	ffc := &TopicFeedController{
		log: log,
	}

	routes := map[string]Action{
		"channel_message_created": (*TopicFeedController).MessageSaved,
		"channel_message_update":  (*TopicFeedController).MessageUpdated,
		"channel_message_deleted": (*TopicFeedController).MessageDeleted,
	}

	ffc.routes = routes

	return ffc
}

func (f *TopicFeedController) HandleEvent(event string, data []byte) error {
	f.log.Debug("New Event Recieved %s", event)
	handler, ok := f.routes[event]
	if !ok {
		return HandlerNotFoundErr
	}

	cm, err := mapMessage(data)
	if err != nil {
		return err
	}

	res, err := isEligible(cm)
	if err != nil {
		return err
	}

	if !res {
		return nil
	}

	return handler(f, cm)
}

func (f *TopicFeedController) MessageSaved(data *models.ChannelMessage) error {

	res := topicRegex.FindAllStringSubmatch(data.Body, -1)
	if len(res) == 0 {
		f.log.Debug("Message doesnt have any topic Body: %s", data.Body)
		return nil
	}

	c, err := fetchChannel(data.InitialChannelId)
	if err != nil {
		return err
	}

	topics := map[string]struct{}{}

	for _, ele := range res {
		topics[ele[1]] = struct{}{}
	}

	for topic := range topics {
		channelName := topic
		tc, err := fetchTopicChannel(c.Group, channelName)
		if err != nil && err != gorm.RecordNotFound {
			return err
		}

		if err == gorm.RecordNotFound {
			tc, err = createTopicChannel(data.AccountId, c.Group, channelName, c.Privacy)
			if err != nil {
				return err
			}
		}

		_, err = tc.AddMessage(data.Id)
		if err != nil {
			return err
		}

	}

	return nil
}

func (f *TopicFeedController) MessageUpdated(data *models.ChannelMessage) error {
	fmt.Println("update", data.InitialChannelId)
	return nil
}

func deleteChannelMessages(channels []models.Channel, data *models.ChannelMessage, toBeDeletedTopics []string) error {
	for _, channel := range channels {
		for _, topic := range toBeDeletedTopics {
			if channel.Name != topic {
				continue
			}

			cml := models.NewChannelMessageList()
			selector := map[string]interface{}{
				"mesage_id":  data.Id,
				"channel_id": channel.Id,
			}

			if err := cml.DeleteMessagesBySelector(selector); err != nil {
				return err
			}
		}
	}
	return nil
}
func getTopicDiff(channels []models.Channel, topics []string) map[string][]string {
	res := make(map[string][]string)

	// aggregate all channel names into map
	channelNames := map[string]struct{}{}
	for _, channel := range channels {
		channelNames[channel.Name] = struct{}{}
	}

	// range over new topics, bacause we are gonna remove
	// unused channels
	for _, topic := range topics {
		found := false
		for channelName := range channelNames {
			if channelName == topic {
				found = true
			}
		}
		if !found {
			res["added"] = append(res["added"], topic)
		} else {
			// if we have topic in channels
			// do remove it because at the end we are gonna mark
			// channels as deleted which are still in channelNames
			delete(channelNames, topic)
		}
	}
	// flatten the deleted channel names
	for channelName := range channelNames {
		res["deleted"] = append(res["deleted"], channelName)
	}

	return res
}

func (f *TopicFeedController) MessageDeleted(data *models.ChannelMessage) error {
	cml := models.NewChannelMessageList()
	selector := map[string]interface{}{
		"mesage_id": data.Id,
	}

	if err := cml.DeleteMessagesBySelector(selector); err != nil {
		return err
	}
	return nil
}

func mapMessage(data []byte) (*models.ChannelMessage, error) {
	cm := models.NewChannelMessage()
	if err := json.Unmarshal(data, cm); err != nil {
		return nil, err
	}

	return cm, nil
}

func isEligible(cm *models.ChannelMessage) (bool, error) {
	if cm.InitialChannelId == 0 {
		return false, nil
	}

	if cm.Type != models.ChannelMessage_TYPE_POST {
		return false, nil
	}

	return true, nil
}

// todo add caching here
func fetchChannel(channelId int64) (*models.Channel, error) {
	c := models.NewChannel()
	c.Id = channelId
	// todo - fetch only name here
	if err := c.Fetch(); err != nil {
		return nil, err
	}

	return c, nil
}

// todo add caching here
func fetchTopicChannel(groupName, channelName string) (*models.Channel, error) {
	c := models.NewChannel()

	selector := map[string]interface{}{
		"group": groupName,
		"name":  channelName,
		"type":  models.Channel_TYPE_TOPIC,
	}

	err := c.One(selector)
	if err != nil {
		return nil, err
	}

	return c, nil
}

func createTopicChannel(creatorId int64, groupName, channelName, privacy string) (*models.Channel, error) {
	c := models.NewChannel()
	c.Name = channelName
	c.CreatorId = creatorId
	c.Group = groupName
	c.Purpose = fmt.Sprintf("Channel for %s topic", channelName)
	c.Type = models.Channel_TYPE_TOPIC
	c.Privacy = privacy
	if err := c.Create(); err != nil {
		return nil, err
	}

	return c, nil
}
<|endoftext|>


<commit_before>package syslogparser

import (
	. "launchpad.net/gocheck"
	"time"
)

type Rfc3164TestSuite struct {
}

var _ = Suite(&Rfc3164TestSuite{})

func (s *Rfc3164TestSuite) TestParseTimestamp_TooLong(c *C) {
	// XXX : <15 chars
	buff := []byte("aaa")
	start := 0
	ts := new(time.Time)

	assertTimestamp(c, *ts, buff, start, len(buff), ErrEOL)
}

func (s *Rfc3164TestSuite) TestParseTimestamp_Invalid(c *C) {
	buff := []byte("Oct 34 32:72:82")
	start := 0
	ts := new(time.Time)

	assertTimestamp(c, *ts, buff, start, len(buff), ErrTimestampUnknownFormat)
}

func (s *Rfc3164TestSuite) TestParseTimestamp_Valid(c *C) {
	// XXX : no year specified. Assumed current year
	// XXX : no timezone specified. Assume UTC
	buff := []byte("Oct 11 22:14:15")
	start := 0

	now := time.Now()
	ts := time.Date(now.Year(), time.October, 11, 22, 14, 15, 0, time.UTC)

	assertTimestamp(c, ts, buff, start, len(buff), nil)
}

func (s *Rfc3164TestSuite) TestParseHostname_Invalid(c *C) {
	// XXX : no year specified. Assumed current year
	// XXX : no timezone specified. Assume UTC
	buff := []byte("host name")
	start := 0
	hostname := "host"

	assertHostname(c, hostname, buff, start, len("host")+1, nil)
}

func (s *Rfc3164TestSuite) TestParseHostname_Valid(c *C) {
	// XXX : no year specified. Assumed current year
	// XXX : no timezone specified. Assume UTC
	buff := []byte("ubuntu11.somehost.com")
	start := 0
	hostname := string(buff)

	assertHostname(c, hostname, buff, start, len(buff), nil)
}

func (s *Rfc3164TestSuite) BenchmarkParseTimestamp(c *C) {
	buff := []byte("Oct 11 22:14:15")
	var start int
	l := len(buff)

	for i := 0; i < c.N; i++ {
		start = 0
		_, err := parseTimestamp(buff, &start, l)
		if err != nil {
			panic(err)
		}
	}
}

func assertTimestamp(c *C, ts time.Time, b []byte, s int, expS int, e error) {
	obtained, err := parseTimestamp(b, &s, len(b))
	c.Assert(obtained, Equals, ts)
	c.Assert(s, Equals, expS)
	c.Assert(err, Equals, e)
}

func assertHostname(c *C, h string, b []byte, s int, expS int, e error) {
	obtained, err := parseHostname(b, &s, len(b))
	c.Assert(obtained, Equals, h)
	c.Assert(s, Equals, expS)
	c.Assert(err, Equals, e)
}
<commit_msg>Added BenchmarkParseHostname<commit_after>package syslogparser

import (
	. "launchpad.net/gocheck"
	"time"
)

type Rfc3164TestSuite struct {
}

var _ = Suite(&Rfc3164TestSuite{})

func (s *Rfc3164TestSuite) TestParseTimestamp_TooLong(c *C) {
	// XXX : <15 chars
	buff := []byte("aaa")
	start := 0
	ts := new(time.Time)

	assertTimestamp(c, *ts, buff, start, len(buff), ErrEOL)
}

func (s *Rfc3164TestSuite) TestParseTimestamp_Invalid(c *C) {
	buff := []byte("Oct 34 32:72:82")
	start := 0
	ts := new(time.Time)

	assertTimestamp(c, *ts, buff, start, len(buff), ErrTimestampUnknownFormat)
}

func (s *Rfc3164TestSuite) TestParseTimestamp_Valid(c *C) {
	// XXX : no year specified. Assumed current year
	// XXX : no timezone specified. Assume UTC
	buff := []byte("Oct 11 22:14:15")
	start := 0

	now := time.Now()
	ts := time.Date(now.Year(), time.October, 11, 22, 14, 15, 0, time.UTC)

	assertTimestamp(c, ts, buff, start, len(buff), nil)
}

func (s *Rfc3164TestSuite) TestParseHostname_Invalid(c *C) {
	// XXX : no year specified. Assumed current year
	// XXX : no timezone specified. Assume UTC
	buff := []byte("host name")
	start := 0
	hostname := "host"

	assertHostname(c, hostname, buff, start, len("host")+1, nil)
}

func (s *Rfc3164TestSuite) TestParseHostname_Valid(c *C) {
	// XXX : no year specified. Assumed current year
	// XXX : no timezone specified. Assume UTC
	buff := []byte("ubuntu11.somehost.com")
	start := 0
	hostname := string(buff)

	assertHostname(c, hostname, buff, start, len(buff), nil)
}

func (s *Rfc3164TestSuite) BenchmarkParseTimestamp(c *C) {
	buff := []byte("Oct 11 22:14:15")
	var start int
	l := len(buff)

	for i := 0; i < c.N; i++ {
		start = 0
		_, err := parseTimestamp(buff, &start, l)
		if err != nil {
			panic(err)
		}
	}
}

func (s *Rfc3164TestSuite) BenchmarkParseHostname(c *C) {
	buff := []byte("gimli.local")
	var start int
	l := len(buff)

	for i := 0; i < c.N; i++ {
		start = 0
		_, err := parseHostname(buff, &start, l)
		if err != nil {
			panic(err)
		}
	}
}

func assertTimestamp(c *C, ts time.Time, b []byte, s int, expS int, e error) {
	obtained, err := parseTimestamp(b, &s, len(b))
	c.Assert(obtained, Equals, ts)
	c.Assert(s, Equals, expS)
	c.Assert(err, Equals, e)
}

func assertHostname(c *C, h string, b []byte, s int, expS int, e error) {
	obtained, err := parseHostname(b, &s, len(b))
	c.Assert(obtained, Equals, h)
	c.Assert(s, Equals, expS)
	c.Assert(err, Equals, e)
}
<|endoftext|>