<commit_before>/*
Copyright 2021 The Vitess Authors.

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 collations

import (
	"fmt"
	"strings"
	"sync"
)

type colldefaults struct {
	Default Collation
	Binary  Collation
}

// Environment is a collation environment for a MySQL version, which contains
// a database of collations and defaults for that specific version.
type Environment struct {
	version     collver
	byName      map[string]Collation
	byID        map[ID]Collation
	byCharset   map[string]*colldefaults
	unsupported map[string]ID
}

// LookupByName returns the collation with the given name. The collation
// is initialized if it's the first time being accessed.
func (env *Environment) LookupByName(name string) Collation {
	if coll, ok := env.byName[name]; ok {
		coll.Init()
		return coll
	}
	return nil
}

// LookupByID returns the collation with the given numerical identifier. The collation
// is initialized if it's the first time being accessed.
func (env *Environment) LookupByID(id ID) Collation {
	if coll, ok := env.byID[id]; ok {
		coll.Init()
		return coll
	}
	return nil
}

// LookupID returns the collation ID for the given name, and whether
// the collation is supported by this package.
func (env *Environment) LookupID(name string) (ID, bool) {
	if supported, ok := env.byName[name]; ok {
		return supported.ID(), true
	}
	if unsupported, ok := env.unsupported[name]; ok {
		return unsupported, false
	}
	return Unknown, false
}

// DefaultCollationForCharset returns the default collation for a charset
func (env *Environment) DefaultCollationForCharset(charset string) Collation {
	if defaults, ok := env.byCharset[charset]; ok {
		if defaults.Default != nil {
			defaults.Default.Init()
			return defaults.Default
		}
	}
	return nil
}

// BinaryCollationForCharset returns the default binary collation for a charset
func (env *Environment) BinaryCollationForCharset(charset string) Collation {
	if defaults, ok := env.byCharset[charset]; ok {
		if defaults.Binary != nil {
			defaults.Binary.Init()
			return defaults.Binary
		}
	}
	return nil
}

// AllCollations returns a slice with all known collations in Vitess. This is an expensive call because
// it will initialize the internal state of all the collations before returning them.
// Used for testing/debugging.
func (env *Environment) AllCollations() (all []Collation) {
	all = make([]Collation, 0, len(env.byID))
	for _, col := range env.byID {
		col.Init()
		all = append(all, col)
	}
	return
}

// NewEnvironment creates a collation Environment for the given MySQL version string.
// The version string must be in the format that is sent by the server as the version packet
// when opening a new MySQL connection
func NewEnvironment(serverVersion string) (*Environment, error) {
	var version collver
	switch {
	case strings.Contains(serverVersion, "MariaDB"):
		switch {
		case strings.HasPrefix(serverVersion, "10.0."):
			version = collverMariaDB100
		case strings.HasPrefix(serverVersion, "10.1."):
			version = collverMariaDB101
		case strings.HasPrefix(serverVersion, "10.2."):
			version = collverMariaDB102
		case strings.HasPrefix(serverVersion, "10.3."):
			version = collverMariaDB103
		}
	case strings.HasPrefix(serverVersion, "5.6."):
		version = collverMySQL56
	case strings.HasPrefix(serverVersion, "5.7."):
		version = collverMySQL57
	case strings.HasPrefix(serverVersion, "8.0."):
		version = collverMySQL80
	}
	if version == collverInvalid {
		return nil, fmt.Errorf("unknown ServerVersion value: %q", serverVersion)
	}
	return makeEnv(version), nil
}

func makeEnv(version collver) *Environment {
	env := &Environment{
		version:     version,
		byName:      make(map[string]Collation),
		byID:        make(map[ID]Collation),
		byCharset:   make(map[string]*colldefaults),
		unsupported: make(map[string]ID),
	}

	for collid, vi := range globalVersionInfo {
		var ourname string
		for mask, name := range vi.alias {
			if mask&version != 0 {
				ourname = name
				break
			}
		}
		if ourname == "" {
			continue
		}

		collation, ok := globalAllCollations[collid]
		if !ok {
			env.unsupported[ourname] = collid
			continue
		}

		env.byName[ourname] = collation
		env.byID[collid] = collation

		csname := collation.Charset().Name()
		if _, ok := env.byCharset[csname]; !ok {
			env.byCharset[csname] = &colldefaults{}
		}
		defaults := env.byCharset[csname]
		if vi.isdefault&version != 0 {
			defaults.Default = collation
		}
		if collation.IsBinary() {
			if defaults.Binary != nil && defaults.Binary.ID() > collation.ID() {
				// If there's more than one binary collation, the one with the
				// highest ID (i.e. the newest one) takes precedence. This applies
				// to utf8mb4_bin vs utf8mb4_0900_bin
				continue
			}
			defaults.Binary = collation
		}
	}
	return env
}

var globalDefault *Environment
var globalDefaultInit sync.Once

// Default is the default collation Environment for Vitess. This is set to
// the collation set and defaults available in MySQL 8.0
func Default() *Environment {
	globalDefaultInit.Do(func() {
		globalDefault = makeEnv(collverMySQL80)
	})
	return globalDefault
}
<commit_msg>collations: use a cache for environment versions<commit_after>/*
Copyright 2021 The Vitess Authors.

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 collations

import (
	"fmt"
	"strings"
	"sync"
)

type colldefaults struct {
	Default Collation
	Binary  Collation
}

// Environment is a collation environment for a MySQL version, which contains
// a database of collations and defaults for that specific version.
type Environment struct {
	version     collver
	byName      map[string]Collation
	byID        map[ID]Collation
	byCharset   map[string]*colldefaults
	unsupported map[string]ID
}

// LookupByName returns the collation with the given name. The collation
// is initialized if it's the first time being accessed.
func (env *Environment) LookupByName(name string) Collation {
	if coll, ok := env.byName[name]; ok {
		coll.Init()
		return coll
	}
	return nil
}

// LookupByID returns the collation with the given numerical identifier. The collation
// is initialized if it's the first time being accessed.
func (env *Environment) LookupByID(id ID) Collation {
	if coll, ok := env.byID[id]; ok {
		coll.Init()
		return coll
	}
	return nil
}

// LookupID returns the collation ID for the given name, and whether
// the collation is supported by this package.
func (env *Environment) LookupID(name string) (ID, bool) {
	if supported, ok := env.byName[name]; ok {
		return supported.ID(), true
	}
	if unsupported, ok := env.unsupported[name]; ok {
		return unsupported, false
	}
	return Unknown, false
}

// DefaultCollationForCharset returns the default collation for a charset
func (env *Environment) DefaultCollationForCharset(charset string) Collation {
	if defaults, ok := env.byCharset[charset]; ok {
		if defaults.Default != nil {
			defaults.Default.Init()
			return defaults.Default
		}
	}
	return nil
}

// BinaryCollationForCharset returns the default binary collation for a charset
func (env *Environment) BinaryCollationForCharset(charset string) Collation {
	if defaults, ok := env.byCharset[charset]; ok {
		if defaults.Binary != nil {
			defaults.Binary.Init()
			return defaults.Binary
		}
	}
	return nil
}

// AllCollations returns a slice with all known collations in Vitess. This is an expensive call because
// it will initialize the internal state of all the collations before returning them.
// Used for testing/debugging.
func (env *Environment) AllCollations() (all []Collation) {
	all = make([]Collation, 0, len(env.byID))
	for _, col := range env.byID {
		col.Init()
		all = append(all, col)
	}
	return
}

var globalEnvironments = make(map[collver]*Environment)
var globalEnvironmentsMu sync.Mutex

// fetchCacheEnvironment returns a cached Environment from a global cache.
// We can keep a single Environment per collver version because Environment
// objects are immutable once constructed.
func fetchCacheEnvironment(version collver) *Environment {
	globalEnvironmentsMu.Lock()
	defer globalEnvironmentsMu.Unlock()

	var env *Environment
	if env = globalEnvironments[version]; env == nil {
		env = makeEnv(version)
		globalEnvironments[version] = env
	}
	return env
}

// NewEnvironment creates a collation Environment for the given MySQL version string.
// The version string must be in the format that is sent by the server as the version packet
// when opening a new MySQL connection
func NewEnvironment(serverVersion string) (*Environment, error) {
	var version collver
	switch {
	case strings.Contains(serverVersion, "MariaDB"):
		switch {
		case strings.HasPrefix(serverVersion, "10.0."):
			version = collverMariaDB100
		case strings.HasPrefix(serverVersion, "10.1."):
			version = collverMariaDB101
		case strings.HasPrefix(serverVersion, "10.2."):
			version = collverMariaDB102
		case strings.HasPrefix(serverVersion, "10.3."):
			version = collverMariaDB103
		}
	case strings.HasPrefix(serverVersion, "5.6."):
		version = collverMySQL56
	case strings.HasPrefix(serverVersion, "5.7."):
		version = collverMySQL57
	case strings.HasPrefix(serverVersion, "8.0."):
		version = collverMySQL80
	}
	if version == collverInvalid {
		return nil, fmt.Errorf("unknown ServerVersion value: %q", serverVersion)
	}
	return fetchCacheEnvironment(version), nil
}

func makeEnv(version collver) *Environment {
	env := &Environment{
		version:     version,
		byName:      make(map[string]Collation),
		byID:        make(map[ID]Collation),
		byCharset:   make(map[string]*colldefaults),
		unsupported: make(map[string]ID),
	}

	for collid, vi := range globalVersionInfo {
		var ourname string
		for mask, name := range vi.alias {
			if mask&version != 0 {
				ourname = name
				break
			}
		}
		if ourname == "" {
			continue
		}

		collation, ok := globalAllCollations[collid]
		if !ok {
			env.unsupported[ourname] = collid
			continue
		}

		env.byName[ourname] = collation
		env.byID[collid] = collation

		csname := collation.Charset().Name()
		if _, ok := env.byCharset[csname]; !ok {
			env.byCharset[csname] = &colldefaults{}
		}
		defaults := env.byCharset[csname]
		if vi.isdefault&version != 0 {
			defaults.Default = collation
		}
		if collation.IsBinary() {
			if defaults.Binary != nil && defaults.Binary.ID() > collation.ID() {
				// If there's more than one binary collation, the one with the
				// highest ID (i.e. the newest one) takes precedence. This applies
				// to utf8mb4_bin vs utf8mb4_0900_bin
				continue
			}
			defaults.Binary = collation
		}
	}
	return env
}

// Default is the default collation Environment for Vitess. This is set to
// the collation set and defaults available in MySQL 8.0
func Default() *Environment {
	return fetchCacheEnvironment(collverMySQL80)
}
<|endoftext|>


<commit_before>package sqlite

import (
	"database/sql"
	"os"
	"strings"
	"testing"
	"time"
)

func TestOpen(t *testing.T) {
	db, err := sql.Open("sqlite3", "./foo.db")
	if err != nil {
		t.Error("Failed to open database:", err)
		return
	}
	defer os.Remove("./foo.db")

	_, err = db.Exec("drop table foo")
	_, err = db.Exec("create table foo (id integer)")
	if err != nil {
		t.Error("Failed to create table:", err)
		return
	}

	if stat, err := os.Stat("./foo.db"); err != nil || stat.IsDir() {
		t.Error("Failed to create ./foo.db")
	}
}

func TestInsert(t *testing.T) {
	db, err := sql.Open("sqlite3", "./foo.db")
	if err != nil {
		t.Error("Failed to open database:", err)
		return
	}
	defer os.Remove("./foo.db")

	_, err = db.Exec("drop table foo")
	_, err = db.Exec("create table foo (id integer)")
	if err != nil {
		t.Error("Failed to create table:", err)
		return
	}

	res, err := db.Exec("insert into foo(id) values(123)")
	if err != nil {
		t.Error("Failed to insert record:", err)
		return
	}
	affected, _ := res.RowsAffected()
	if affected != 1 {
		t.Errorf("Expected %d for affected rows, but %d:", 1, affected)
		return
	}

	rows, err := db.Query("select id from foo")
	if err != nil {
		t.Error("Failed to select records:", err)
		return
	}
	defer rows.Close()

	rows.Next()

	var result int
	rows.Scan(&result)
	if result != 123 {
		t.Errorf("Fetched %q; expected %q", 123, result)
	}
}

func TestUpdate(t *testing.T) {
	db, err := sql.Open("sqlite3", "./foo.db")
	if err != nil {
		t.Error("Failed to open database:", err)
		return
	}
	defer os.Remove("./foo.db")

	_, err = db.Exec("drop table foo")
	_, err = db.Exec("create table foo (id integer)")
	if err != nil {
		t.Error("Failed to create table:", err)
		return
	}

	res, err := db.Exec("insert into foo(id) values(123)")
	if err != nil {
		t.Error("Failed to insert record:", err)
		return
	}
	expected, err := res.LastInsertId()
	if err != nil {
		t.Error("Failed to get LastInsertId:", err)
		return
	}
	affected, _ := res.RowsAffected()
	if err != nil {
		t.Error("Failed to get RowsAffected:", err)
		return
	}
	if affected != 1 {
		t.Errorf("Expected %d for affected rows, but %d:", 1, affected)
		return
	}

	res, err = db.Exec("update foo set id = 234")
	if err != nil {
		t.Error("Failed to update record:", err)
		return
	}
	lastId, err := res.LastInsertId()
	if err != nil {
		t.Error("Failed to get LastInsertId:", err)
		return
	}
	if expected != lastId {
		t.Errorf("Expected %q for last Id, but %q:", expected, lastId)
	}
	affected, _ = res.RowsAffected()
	if err != nil {
		t.Error("Failed to get RowsAffected:", err)
		return
	}
	if affected != 1 {
		t.Errorf("Expected %d for affected rows, but %d:", 1, affected)
		return
	}

	rows, err := db.Query("select id from foo")
	if err != nil {
		t.Error("Failed to select records:", err)
		return
	}
	defer rows.Close()

	rows.Next()

	var result int
	rows.Scan(&result)
	if result != 234 {
		t.Errorf("Fetched %q; expected %q", 234, result)
	}
}

func TestDelete(t *testing.T) {
	db, err := sql.Open("sqlite3", "./foo.db")
	if err != nil {
		t.Error("Failed to open database:", err)
		return
	}
	defer os.Remove("./foo.db")

	_, err = db.Exec("drop table foo")
	_, err = db.Exec("create table foo (id integer)")
	if err != nil {
		t.Error("Failed to create table:", err)
		return
	}

	res, err := db.Exec("insert into foo(id) values(123)")
	if err != nil {
		t.Error("Failed to insert record:", err)
		return
	}
	expected, err := res.LastInsertId()
	if err != nil {
		t.Error("Failed to get LastInsertId:", err)
		return
	}
	affected, err := res.RowsAffected()
	if err != nil {
		t.Error("Failed to get RowsAffected:", err)
		return
	}
	if affected != 1 {
		t.Errorf("Expected %d for cout of affected rows, but %q:", 1, affected)
	}

	res, err = db.Exec("delete from foo where id = 123")
	if err != nil {
		t.Error("Failed to delete record:", err)
		return
	}
	lastId, err := res.LastInsertId()
	if err != nil {
		t.Error("Failed to get LastInsertId:", err)
		return
	}
	if expected != lastId {
		t.Errorf("Expected %q for last Id, but %q:", expected, lastId)
	}
	affected, err = res.RowsAffected()
	if err != nil {
		t.Error("Failed to get RowsAffected:", err)
		return
	}
	if affected != 1 {
		t.Errorf("Expected %d for cout of affected rows, but %q:", 1, affected)
	}

	rows, err := db.Query("select id from foo")
	if err != nil {
		t.Error("Failed to select records:", err)
		return
	}
	defer rows.Close()

	if rows.Next() {
		t.Error("Fetched row but expected not rows")
	}
}

func TestBooleanRoundtrip(t *testing.T) {
	db, err := sql.Open("sqlite3", "./foo.db")
	if err != nil {
		t.Error("Failed to open database:", err)
		return
	}
	defer os.Remove("./foo.db")

	_, err = db.Exec("DROP TABLE foo")
	_, err = db.Exec("CREATE TABLE foo(id INTEGER, value BOOL)")
	if err != nil {
		t.Error("Failed to create table:", err)
		return
	}

	_, err = db.Exec("INSERT INTO foo(id, value) VALUES(1, ?)", true)
	if err != nil {
		t.Error("Failed to insert true value:", err)
		return
	}

	_, err = db.Exec("INSERT INTO foo(id, value) VALUES(2, ?)", false)
	if err != nil {
		t.Error("Failed to insert false value:", err)
		return
	}

	rows, err := db.Query("SELECT id, value FROM foo")
	if err != nil {
		t.Error("Unable to query foo table:", err)
		return
	}

	for rows.Next() {
		var id int
		var value bool

		if err := rows.Scan(&id, &value); err != nil {
			t.Error("Unable to scan results:", err)
			continue
		}

		if id == 1 && !value {
			t.Error("Value for id 1 should be true, not false")

		} else if id == 2 && value {
			t.Error("Value for id 2 should be false, not true")
		}
	}
}

func TestTimestamp(t *testing.T) {
	db, err := sql.Open("sqlite3", "./foo.db")
	if err != nil {
		t.Error("Failed to open database:", err)
		return
	}
	defer os.Remove("./foo.db")

	_, err = db.Exec("DROP TABLE foo")
	_, err = db.Exec("CREATE TABLE foo(id INTEGER, ts timeSTAMP)")
	if err != nil {
		t.Error("Failed to create table:", err)
		return
	}

	timestamp1 := time.Date(2012, time.April, 6, 22, 50, 0, 0, time.UTC)
	_, err = db.Exec("INSERT INTO foo(id, ts) VALUES(1, ?)", timestamp1)
	if err != nil {
		t.Error("Failed to insert timestamp:", err)
		return
	}

	timestamp2 := time.Date(2012, time.April, 6, 23, 22, 0, 0, time.UTC)
	_, err = db.Exec("INSERT INTO foo(id, ts) VALUES(2, ?)", timestamp2.Unix())
	if err != nil {
		t.Error("Failed to insert timestamp:", err)
		return
	}

	_, err = db.Exec("INSERT INTO foo(id, ts) VALUES(3, ?)", "nonsense")
	if err != nil {
		t.Error("Failed to insert nonsense:", err)
		return
	}

	rows, err := db.Query("SELECT id, ts FROM foo ORDER BY id ASC")
	if err != nil {
		t.Error("Unable to query foo table:", err)
		return
	}

	seen := 0
	for rows.Next() {
		var id int
		var ts time.Time

		if err := rows.Scan(&id, &ts); err != nil {
			t.Error("Unable to scan results:", err)
			continue
		}

		if id == 1 {
			seen += 1
			if !timestamp1.Equal(ts) {
				t.Errorf("Value for id 1 should be %v, not %v", timestamp1, ts)
			}
		}

		if id == 2 {
			seen += 1
			if !timestamp2.Equal(ts) {
				t.Errorf("Value for id 2 should be %v, not %v", timestamp2, ts)
			}
		}
	}

	if seen != 2 {
		t.Error("Expected to see two valid timestamps")
	}

	// make sure "nonsense" triggered an error
	err = rows.Err()
	if err == nil || !strings.Contains(err.Error(), "cannot parse \"nonsense\"") {
		t.Error("Expected error from \"nonsense\" timestamp")
	}
}

func TestBoolean(t *testing.T) {
	db, err := sql.Open("sqlite3", "./foo.db")
	if err != nil {
		t.Error("Failed to open database:", err)
		return
	}

	defer os.Remove("./foo.db")

	_, err = db.Exec("CREATE TABLE foo(id INTEGER, fbool BOOLEAN)")
	if err != nil {
		t.Error("Failed to create table:", err)
		return
	}

	bool1 := true
	_, err = db.Exec("INSERT INTO foo(id, fbool) VALUES(1, ?)", bool1)
	if err != nil {
		t.Error("Failed to insert boolean:", err)
		return
	}

	bool2 := false
	_, err = db.Exec("INSERT INTO foo(id, fbool) VALUES(2, ?)", bool2)
	if err != nil {
		t.Error("Failed to insert boolean:", err)
		return
	}

	bool3 := "nonsense"
	_, err = db.Exec("INSERT INTO foo(id, fbool) VALUES(3, ?)", bool3)
	if err != nil {
		t.Error("Failed to insert nonsense:", err)
		return
	}

	rows, err := db.Query("SELECT id, fbool FROM foo where fbool is ?", bool1)
	if err != nil {
		t.Error("Unable to query foo table:", err)
		return
	}
	counter := 0

	var id int
	var fbool bool

	for rows.Next() {
		if err := rows.Scan(&id, &fbool); err != nil {
			t.Error("Unable to scan results:", err)
			return
		}
		counter++
	}

	if counter != 1 {
		t.Errorf("Expected 1 row but %v", counter)
		return
	}

	if id != 1 && fbool != true {
		t.Errorf("Value for id 1 should be %v, not %v", bool1, fbool)
		return
	}

	rows, err = db.Query("SELECT id, fbool FROM foo where fbool is ?", bool2)
	if err != nil {
		t.Error("Unable to query foo table:", err)
		return
	}

	counter = 0

	for rows.Next() {
		if err := rows.Scan(&id, &fbool); err != nil {
			t.Error("Unable to scan results:", err)
			return
		}
		counter++
	}

	if counter != 1 {
		t.Errorf("Expected 1 row but %v", counter)
		return
	}

	if id != 2 && fbool != false {
		t.Errorf("Value for id 2 should be %v, not %v", bool2, fbool)
		return
	}

	// make sure "nonsense" triggered an error
	rows, err = db.Query("SELECT id, fbool FROM foo where id=?;", 3)
	if err != nil {
		t.Error("Unable to query foo table:", err)
		return
	}

	rows.Next()
	err = rows.Scan(&id, &fbool)
	if err == nil {
		t.Error("Expected error from \"nonsense\" bool")
	}
}
<commit_msg>Added missing db.Close() and rows.Close() calls; fixes tests on vmhgfs filesystems.<commit_after>package sqlite

import (
	"database/sql"
	"os"
	"strings"
	"testing"
	"time"
)

func TestOpen(t *testing.T) {
	db, err := sql.Open("sqlite3", "./foo.db")
	if err != nil {
		t.Error("Failed to open database:", err)
		return
	}
	defer os.Remove("./foo.db")
	defer db.Close()

	_, err = db.Exec("drop table foo")
	_, err = db.Exec("create table foo (id integer)")
	if err != nil {
		t.Error("Failed to create table:", err)
		return
	}

	if stat, err := os.Stat("./foo.db"); err != nil || stat.IsDir() {
		t.Error("Failed to create ./foo.db")
	}
}

func TestInsert(t *testing.T) {
	db, err := sql.Open("sqlite3", "./foo.db")
	if err != nil {
		t.Error("Failed to open database:", err)
		return
	}
	defer os.Remove("./foo.db")
	defer db.Close()

	_, err = db.Exec("drop table foo")
	_, err = db.Exec("create table foo (id integer)")
	if err != nil {
		t.Error("Failed to create table:", err)
		return
	}

	res, err := db.Exec("insert into foo(id) values(123)")
	if err != nil {
		t.Error("Failed to insert record:", err)
		return
	}
	affected, _ := res.RowsAffected()
	if affected != 1 {
		t.Errorf("Expected %d for affected rows, but %d:", 1, affected)
		return
	}

	rows, err := db.Query("select id from foo")
	if err != nil {
		t.Error("Failed to select records:", err)
		return
	}
	defer rows.Close()

	rows.Next()

	var result int
	rows.Scan(&result)
	if result != 123 {
		t.Errorf("Fetched %q; expected %q", 123, result)
	}
}

func TestUpdate(t *testing.T) {
	db, err := sql.Open("sqlite3", "./foo.db")
	if err != nil {
		t.Error("Failed to open database:", err)
		return
	}
	defer os.Remove("./foo.db")
	defer db.Close()

	_, err = db.Exec("drop table foo")
	_, err = db.Exec("create table foo (id integer)")
	if err != nil {
		t.Error("Failed to create table:", err)
		return
	}

	res, err := db.Exec("insert into foo(id) values(123)")
	if err != nil {
		t.Error("Failed to insert record:", err)
		return
	}
	expected, err := res.LastInsertId()
	if err != nil {
		t.Error("Failed to get LastInsertId:", err)
		return
	}
	affected, _ := res.RowsAffected()
	if err != nil {
		t.Error("Failed to get RowsAffected:", err)
		return
	}
	if affected != 1 {
		t.Errorf("Expected %d for affected rows, but %d:", 1, affected)
		return
	}

	res, err = db.Exec("update foo set id = 234")
	if err != nil {
		t.Error("Failed to update record:", err)
		return
	}
	lastId, err := res.LastInsertId()
	if err != nil {
		t.Error("Failed to get LastInsertId:", err)
		return
	}
	if expected != lastId {
		t.Errorf("Expected %q for last Id, but %q:", expected, lastId)
	}
	affected, _ = res.RowsAffected()
	if err != nil {
		t.Error("Failed to get RowsAffected:", err)
		return
	}
	if affected != 1 {
		t.Errorf("Expected %d for affected rows, but %d:", 1, affected)
		return
	}

	rows, err := db.Query("select id from foo")
	if err != nil {
		t.Error("Failed to select records:", err)
		return
	}
	defer rows.Close()

	rows.Next()

	var result int
	rows.Scan(&result)
	if result != 234 {
		t.Errorf("Fetched %q; expected %q", 234, result)
	}
}

func TestDelete(t *testing.T) {
	db, err := sql.Open("sqlite3", "./foo.db")
	if err != nil {
		t.Error("Failed to open database:", err)
		return
	}
	defer os.Remove("./foo.db")
	defer db.Close()

	_, err = db.Exec("drop table foo")
	_, err = db.Exec("create table foo (id integer)")
	if err != nil {
		t.Error("Failed to create table:", err)
		return
	}

	res, err := db.Exec("insert into foo(id) values(123)")
	if err != nil {
		t.Error("Failed to insert record:", err)
		return
	}
	expected, err := res.LastInsertId()
	if err != nil {
		t.Error("Failed to get LastInsertId:", err)
		return
	}
	affected, err := res.RowsAffected()
	if err != nil {
		t.Error("Failed to get RowsAffected:", err)
		return
	}
	if affected != 1 {
		t.Errorf("Expected %d for cout of affected rows, but %q:", 1, affected)
	}

	res, err = db.Exec("delete from foo where id = 123")
	if err != nil {
		t.Error("Failed to delete record:", err)
		return
	}
	lastId, err := res.LastInsertId()
	if err != nil {
		t.Error("Failed to get LastInsertId:", err)
		return
	}
	if expected != lastId {
		t.Errorf("Expected %q for last Id, but %q:", expected, lastId)
	}
	affected, err = res.RowsAffected()
	if err != nil {
		t.Error("Failed to get RowsAffected:", err)
		return
	}
	if affected != 1 {
		t.Errorf("Expected %d for cout of affected rows, but %q:", 1, affected)
	}

	rows, err := db.Query("select id from foo")
	if err != nil {
		t.Error("Failed to select records:", err)
		return
	}
	defer rows.Close()

	if rows.Next() {
		t.Error("Fetched row but expected not rows")
	}
}

func TestBooleanRoundtrip(t *testing.T) {
	db, err := sql.Open("sqlite3", "./foo.db")
	if err != nil {
		t.Error("Failed to open database:", err)
		return
	}
	defer os.Remove("./foo.db")
	defer db.Close()

	_, err = db.Exec("DROP TABLE foo")
	_, err = db.Exec("CREATE TABLE foo(id INTEGER, value BOOL)")
	if err != nil {
		t.Error("Failed to create table:", err)
		return
	}

	_, err = db.Exec("INSERT INTO foo(id, value) VALUES(1, ?)", true)
	if err != nil {
		t.Error("Failed to insert true value:", err)
		return
	}

	_, err = db.Exec("INSERT INTO foo(id, value) VALUES(2, ?)", false)
	if err != nil {
		t.Error("Failed to insert false value:", err)
		return
	}

	rows, err := db.Query("SELECT id, value FROM foo")
	if err != nil {
		t.Error("Unable to query foo table:", err)
		return
	}
	defer rows.Close()

	for rows.Next() {
		var id int
		var value bool

		if err := rows.Scan(&id, &value); err != nil {
			t.Error("Unable to scan results:", err)
			continue
		}

		if id == 1 && !value {
			t.Error("Value for id 1 should be true, not false")

		} else if id == 2 && value {
			t.Error("Value for id 2 should be false, not true")
		}
	}
}

func TestTimestamp(t *testing.T) {
	db, err := sql.Open("sqlite3", "./foo.db")
	if err != nil {
		t.Error("Failed to open database:", err)
		return
	}
	defer os.Remove("./foo.db")
	defer db.Close()

	_, err = db.Exec("DROP TABLE foo")
	_, err = db.Exec("CREATE TABLE foo(id INTEGER, ts timeSTAMP)")
	if err != nil {
		t.Error("Failed to create table:", err)
		return
	}

	timestamp1 := time.Date(2012, time.April, 6, 22, 50, 0, 0, time.UTC)
	_, err = db.Exec("INSERT INTO foo(id, ts) VALUES(1, ?)", timestamp1)
	if err != nil {
		t.Error("Failed to insert timestamp:", err)
		return
	}

	timestamp2 := time.Date(2012, time.April, 6, 23, 22, 0, 0, time.UTC)
	_, err = db.Exec("INSERT INTO foo(id, ts) VALUES(2, ?)", timestamp2.Unix())
	if err != nil {
		t.Error("Failed to insert timestamp:", err)
		return
	}

	_, err = db.Exec("INSERT INTO foo(id, ts) VALUES(3, ?)", "nonsense")
	if err != nil {
		t.Error("Failed to insert nonsense:", err)
		return
	}

	rows, err := db.Query("SELECT id, ts FROM foo ORDER BY id ASC")
	if err != nil {
		t.Error("Unable to query foo table:", err)
		return
	}
	defer rows.Close()

	seen := 0
	for rows.Next() {
		var id int
		var ts time.Time

		if err := rows.Scan(&id, &ts); err != nil {
			t.Error("Unable to scan results:", err)
			continue
		}

		if id == 1 {
			seen += 1
			if !timestamp1.Equal(ts) {
				t.Errorf("Value for id 1 should be %v, not %v", timestamp1, ts)
			}
		}

		if id == 2 {
			seen += 1
			if !timestamp2.Equal(ts) {
				t.Errorf("Value for id 2 should be %v, not %v", timestamp2, ts)
			}
		}
	}

	if seen != 2 {
		t.Error("Expected to see two valid timestamps")
	}

	// make sure "nonsense" triggered an error
	err = rows.Err()
	if err == nil || !strings.Contains(err.Error(), "cannot parse \"nonsense\"") {
		t.Error("Expected error from \"nonsense\" timestamp")
	}
}

func TestBoolean(t *testing.T) {
	db, err := sql.Open("sqlite3", "./foo.db")
	if err != nil {
		t.Error("Failed to open database:", err)
		return
	}

	defer os.Remove("./foo.db")
	defer db.Close()

	_, err = db.Exec("CREATE TABLE foo(id INTEGER, fbool BOOLEAN)")
	if err != nil {
		t.Error("Failed to create table:", err)
		return
	}

	bool1 := true
	_, err = db.Exec("INSERT INTO foo(id, fbool) VALUES(1, ?)", bool1)
	if err != nil {
		t.Error("Failed to insert boolean:", err)
		return
	}

	bool2 := false
	_, err = db.Exec("INSERT INTO foo(id, fbool) VALUES(2, ?)", bool2)
	if err != nil {
		t.Error("Failed to insert boolean:", err)
		return
	}

	bool3 := "nonsense"
	_, err = db.Exec("INSERT INTO foo(id, fbool) VALUES(3, ?)", bool3)
	if err != nil {
		t.Error("Failed to insert nonsense:", err)
		return
	}

	rows, err := db.Query("SELECT id, fbool FROM foo where fbool is ?", bool1)
	if err != nil {
		t.Error("Unable to query foo table:", err)
		return
	}
	counter := 0

	var id int
	var fbool bool

	for rows.Next() {
		if err := rows.Scan(&id, &fbool); err != nil {
			t.Error("Unable to scan results:", err)
			return
		}
		counter++
	}

	if counter != 1 {
		t.Errorf("Expected 1 row but %v", counter)
		return
	}

	if id != 1 && fbool != true {
		t.Errorf("Value for id 1 should be %v, not %v", bool1, fbool)
		return
	}

	rows, err = db.Query("SELECT id, fbool FROM foo where fbool is ?", bool2)
	if err != nil {
		t.Error("Unable to query foo table:", err)
		return
	}

	counter = 0

	for rows.Next() {
		if err := rows.Scan(&id, &fbool); err != nil {
			t.Error("Unable to scan results:", err)
			return
		}
		counter++
	}

	if counter != 1 {
		t.Errorf("Expected 1 row but %v", counter)
		return
	}

	if id != 2 && fbool != false {
		t.Errorf("Value for id 2 should be %v, not %v", bool2, fbool)
		return
	}

	// make sure "nonsense" triggered an error
	rows, err = db.Query("SELECT id, fbool FROM foo where id=?;", 3)
	if err != nil {
		t.Error("Unable to query foo table:", err)
		return
	}

	rows.Next()
	err = rows.Scan(&id, &fbool)
	if err == nil {
		t.Error("Expected error from \"nonsense\" bool")
	}
}
<|endoftext|>


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

package migrations

import (
	"fmt"

	"github.com/go-xorm/xorm"
)

func addCommentIDToAction(x *xorm.Engine) error {
	// Action see models/action.go
	type Action struct {
		CommentID int64 `xorm:"INDEX"`
	}

	if err := x.Sync2(new(Action)); err != nil {
		return fmt.Errorf("Sync2: %v", err)
	}

	return nil
}
<commit_msg>Added improved migration to add a CommentID column to action. Added improved links to comments in feed entries. (+ gofmt)<commit_after>// Copyright 2017 The Gitea Authors. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

package migrations

import (
	"fmt"

	"github.com/go-xorm/xorm"
)

func addCommentIDToAction(x *xorm.Engine) error {
	// Action see models/action.go
	type Action struct {
		CommentID int64 `xorm:"INDEX"`
	}

	if err := x.Sync2(new(Action)); err != nil {
		return fmt.Errorf("Sync2: %v", err)
	}

	return nil
}
<|endoftext|>


<commit_before>// +build integration

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"reflect"
	"testing"
)

var todoAppServer = "http://localhost:3000"

//TestHealthEndpoint checks if the Health endpoint has the right format
func TestHealthEndpoint(t *testing.T) {
	expectedResponse := map[string]string{
		"redis-master": "ok",
		"redis-slave":  "ok",
		"self":         "ok",
	}

	resp, err := http.Get(fmt.Sprintf("%s/health", todoAppServer))
	if err != nil {
		t.Log(err)
		t.FailNow()
	}

	defer resp.Body.Close()
	var Response map[string]string
	if err := json.NewDecoder(resp.Body).Decode(&Response); err != nil {
		t.Log(err)
		t.FailNow()
	}

	if !reflect.DeepEqual(expectedResponse, Response) {
		t.Fail()
	}
}

func TestInsertReadAndDeleteItem(t *testing.T) {
	insertItem := "TestCase"

	// Insert Item
	if _, err := http.Get(fmt.Sprintf("%s/insert/todo/%s", todoAppServer, insertItem)); err != nil {
		t.Log(err)
		t.FailNow()
	}

	// Read Item
	readResp, err := http.Get(fmt.Sprintf("%s/read/todo", todoAppServer))
	if err != nil {
		t.Log(err)
		t.FailNow()
	}

	defer readResp.Body.Close()
	var readResponse []string
	if err := json.NewDecoder(readResp.Body).Decode(&readResponse); err != nil {
		t.Log(err)
		t.FailNow()
	}

	if !reflect.DeepEqual([]string{insertItem}, readResponse) {
		t.FailNow()
	}

	// Delete Item
	deleteResp, err := http.Get(fmt.Sprintf("%s/delete/todo/%s", todoAppServer, insertItem))
	if err != nil {
		t.Log(err)
		t.FailNow()
	}

	defer deleteResp.Body.Close()
	var deleteResponse []string
	if err := json.NewDecoder(deleteResp.Body).Decode(&deleteResponse); err != nil {
		t.Log(err)
		t.FailNow()
	}

	if !reflect.DeepEqual([]string{}, deleteResponse) {
		t.FailNow()
	}
}

//TODO func checkResponse

/* TODO Tests for:
- whoAmIHandler
*/
<commit_msg>Add timeout to HTTP Client<commit_after>// +build integration

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"reflect"
	"testing"
	"time"
)

var todoAppServer = "http://localhost:3000"

func getHTTPClient() *http.Client {
	return &http.Client{
		Timeout: time.Duration(30 * time.Second),
	}
}

//TestHealthEndpoint checks if the Health endpoint has the right format
func TestHealthEndpoint(t *testing.T) {
	expectedResponse := map[string]string{
		"redis-master": "ok",
		"redis-slave":  "ok",
		"self":         "ok",
	}

	resp, err := getHTTPClient().Get(fmt.Sprintf("%s/health", todoAppServer))
	if err != nil {
		t.Log(err)
		t.FailNow()
	}

	defer resp.Body.Close()
	var Response map[string]string
	if err := json.NewDecoder(resp.Body).Decode(&Response); err != nil {
		t.Log(err)
		t.FailNow()
	}

	if !reflect.DeepEqual(expectedResponse, Response) {
		t.Fail()
	}
}

func TestInsertReadAndDeleteItem(t *testing.T) {
	insertItem := "TestCase"

	// Insert Item
	if _, err := getHTTPClient().Get(fmt.Sprintf("%s/insert/todo/%s", todoAppServer, insertItem)); err != nil {
		t.Log(err)
		t.FailNow()
	}

	// Read Item
	readResp, err := getHTTPClient().Get(fmt.Sprintf("%s/read/todo", todoAppServer))
	if err != nil {
		t.Log(err)
		t.FailNow()
	}

	defer readResp.Body.Close()
	var readResponse []string
	if err := json.NewDecoder(readResp.Body).Decode(&readResponse); err != nil {
		t.Log(err)
		t.FailNow()
	}

	if !reflect.DeepEqual([]string{insertItem}, readResponse) {
		t.FailNow()
	}

	// Delete Item
	deleteResp, err := getHTTPClient().Get(fmt.Sprintf("%s/delete/todo/%s", todoAppServer, insertItem))
	if err != nil {
		t.Log(err)
		t.FailNow()
	}

	defer deleteResp.Body.Close()
	var deleteResponse []string
	if err := json.NewDecoder(deleteResp.Body).Decode(&deleteResponse); err != nil {
		t.Log(err)
		t.FailNow()
	}

	if !reflect.DeepEqual([]string{}, deleteResponse) {
		t.FailNow()
	}
}

//TODO func checkResponse

/* TODO Tests for:
- whoAmIHandler
*/
<|endoftext|>


<commit_before>// Copyright (c) 2015 Max Wolter
// Copyright (c) 2015 CIRCL - Computer Incident Response Center Luxembourg
//                           (c/o smile, security made in Lëtzebuerg, Groupement
//                           d'Intérêt Economique)
//
// This file is part of PBTC.
//
// PBTC is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// PBTC is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with PBTC.  If not, see <http://www.gnu.org/licenses/>.

package main

func main() {
}
<commit_msg>Importer skeleton structure<commit_after>// Copyright (c) 2015 Max Wolter
// Copyright (c) 2015 CIRCL - Computer Incident Response Center Luxembourg
//                           (c/o smile, security made in Lëtzebuerg, Groupement
//                           d'Intérêt Economique)
//
// This file is part of PBTC.
//
// PBTC is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// PBTC is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with PBTC.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"bufio"
	"crypto/sha256"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path"

	"github.com/gocql/gocql"
)

var session *gocql.Session

func main() {
	// set the parameters for our cassandra connection
	cluster := gocql.NewCluster("127.0.0.1")
	cluster.DiscoverHosts = true
	cluster.DefaultTimestamp = false

	// establish the cassandra session
	session, err := cluster.CreateSession()
	if err != nil {
		fmt.Println("could not create session")
		os.Exit(1)
	}
	defer session.Close()

	// get a list of iles in the logs folder
	files, err := ioutil.ReadDir("../logs")
	if err != nil {
		fmt.Println("could not read logs folder")
		os.Exit(1)
	}

	// iterate through files for processing
	for _, file := range files {
		err := process(file)
		if err != nil {
			fmt.Printf("%v", err)
		}
	}

	os.Exit(0)
}

func process(file os.FileInfo) error {
	// ignore all directories
	if file.IsDir() {
		return fmt.Errorf("can't process directory: %v", file.Name())
	}

	// ignore all non-log files
	if path.Ext(file.Name()) != ".txt" {
		return fmt.Errorf("can only process log files: %v", file.Name())
	}

	// open file
	f, err := os.Open(file.Name())
	if err != nil {
		return fmt.Errorf("could not open file: %v", file.Name())
	}
	defer f.Close()

	// try to use scanner to read first line
	scanner := bufio.NewScanner(f)
	if !scanner.Scan() {
		return fmt.Errorf("could not read first line: %v", file.Name())
	}

	// check first line header for log version
	line := scanner.Text()
	if line != "PBTC Log Version 1" {
		return fmt.Errorf("unknown header for file: %v (%v)", f.Name(), line)
	}

	// reset file pointer
	_, err = f.Seek(0, 0)
	if err != nil {
		return fmt.Errorf("could not reset file pointer: %v", f.Name())
	}

	// stream file into hasher to get fingerprint
	hasher := sha256.New()
	_, err = io.Copy(hasher, f)
	if err != nil {
		return fmt.Errorf("could not stream file data into hasher: %v", f.Name())
	}

	// get fingerprint hash and check for duplicate
	hash := hasher.Sum(nil)
	fmt.Printf("hash for file: %v - %v", f.Name(), hash)

	// import file into cassandra
	scanner = bufio.NewScanner(f)
	for scanner.Scan() {
		err := insert(scanner.Text())
		if err != nil {
			fmt.Printf("%v", err)
		}
	}

	return nil
}

func insert(line string) error {
	return nil
}
<|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.

//go:build go1.18
// +build go1.18

package main

import (
	"bytes"
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"

	"golang.org/x/tools/gopls/internal/lsp/source"
	diffpkg "golang.org/x/tools/internal/diff"
	"golang.org/x/tools/internal/gocommand"
)

var (
	previousVersionFlag = flag.String("prev", "", "version to compare against")
	versionFlag         = flag.String("version", "", "version being tagged, or current version if omitted")
)

func main() {
	flag.Parse()

	apiDiff, err := diffAPI(*versionFlag, *previousVersionFlag)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf(`
%s
`, apiDiff)
}

type JSON interface {
	String() string
	Write(io.Writer)
}

func diffAPI(version, prev string) (string, error) {
	ctx := context.Background()
	previousApi, err := loadAPI(ctx, prev)
	if err != nil {
		return "", fmt.Errorf("load previous API: %v", err)
	}
	var currentApi *source.APIJSON
	if version == "" {
		currentApi = source.GeneratedAPIJSON
	} else {
		var err error
		currentApi, err = loadAPI(ctx, version)
		if err != nil {
			return "", fmt.Errorf("load current API: %v", err)
		}
	}

	b := &strings.Builder{}
	if err := diff(b, previousApi.Commands, currentApi.Commands, "command", func(c *source.CommandJSON) string {
		return c.Command
	}, diffCommands); err != nil {
		return "", fmt.Errorf("diff commands: %v", err)
	}
	if diff(b, previousApi.Analyzers, currentApi.Analyzers, "analyzer", func(a *source.AnalyzerJSON) string {
		return a.Name
	}, diffAnalyzers); err != nil {
		return "", fmt.Errorf("diff analyzers: %v", err)
	}
	if err := diff(b, previousApi.Lenses, currentApi.Lenses, "code lens", func(l *source.LensJSON) string {
		return l.Lens
	}, diffLenses); err != nil {
		return "", fmt.Errorf("diff lenses: %v", err)
	}
	for key, prev := range previousApi.Options {
		current, ok := currentApi.Options[key]
		if !ok {
			panic(fmt.Sprintf("unexpected option key: %s", key))
		}
		if err := diff(b, prev, current, "option", func(o *source.OptionJSON) string {
			return o.Name
		}, diffOptions); err != nil {
			return "", fmt.Errorf("diff options (%s): %v", key, err)
		}
	}

	return b.String(), nil
}

func diff[T JSON](b *strings.Builder, previous, new []T, kind string, uniqueKey func(T) string, diffFunc func(*strings.Builder, T, T)) error {
	prevJSON := collect(previous, uniqueKey)
	newJSON := collect(new, uniqueKey)
	for k := range newJSON {
		delete(prevJSON, k)
	}
	for _, deleted := range prevJSON {
		b.WriteString(fmt.Sprintf("%s %s was deleted.\n", kind, deleted))
	}
	for _, prev := range previous {
		delete(newJSON, uniqueKey(prev))
	}
	if len(newJSON) > 0 {
		b.WriteString("The following commands were added:\n")
		for _, n := range newJSON {
			n.Write(b)
			b.WriteByte('\n')
		}
	}
	previousMap := collect(previous, uniqueKey)
	for _, current := range new {
		prev, ok := previousMap[uniqueKey(current)]
		if !ok {
			continue
		}
		c, p := bytes.NewBuffer(nil), bytes.NewBuffer(nil)
		prev.Write(p)
		current.Write(c)
		if diff := diffStr(p.String(), c.String()); diff != "" {
			diffFunc(b, prev, current)
			b.WriteString("\n--\n")
		}
	}
	return nil
}

func collect[T JSON](args []T, uniqueKey func(T) string) map[string]T {
	m := map[string]T{}
	for _, arg := range args {
		m[uniqueKey(arg)] = arg
	}
	return m
}

var goCmdRunner = gocommand.Runner{}

func loadAPI(ctx context.Context, version string) (*source.APIJSON, error) {
	tmpGopath, err := ioutil.TempDir("", "gopath*")
	if err != nil {
		return nil, fmt.Errorf("temp dir: %v", err)
	}
	defer os.RemoveAll(tmpGopath)

	exampleDir := fmt.Sprintf("%s/src/example.com", tmpGopath)
	if err := os.MkdirAll(exampleDir, 0776); err != nil {
		return nil, fmt.Errorf("mkdir: %v", err)
	}

	if stdout, err := goCmdRunner.Run(ctx, gocommand.Invocation{
		Verb:       "mod",
		Args:       []string{"init", "example.com"},
		WorkingDir: exampleDir,
		Env:        append(os.Environ(), fmt.Sprintf("GOPATH=%s", tmpGopath)),
	}); err != nil {
		return nil, fmt.Errorf("go mod init failed: %v (stdout: %v)", err, stdout)
	}
	if stdout, err := goCmdRunner.Run(ctx, gocommand.Invocation{
		Verb:       "install",
		Args:       []string{fmt.Sprintf("golang.org/x/tools/gopls@%s", version)},
		WorkingDir: exampleDir,
		Env:        append(os.Environ(), fmt.Sprintf("GOPATH=%s", tmpGopath)),
	}); err != nil {
		return nil, fmt.Errorf("go install failed: %v (stdout: %v)", err, stdout.String())
	}
	cmd := exec.Cmd{
		Path: filepath.Join(tmpGopath, "bin", "gopls"),
		Args: []string{"gopls", "api-json"},
		Dir:  tmpGopath,
	}
	out, err := cmd.Output()
	if err != nil {
		return nil, fmt.Errorf("output: %v", err)
	}
	apiJson := &source.APIJSON{}
	if err := json.Unmarshal(out, apiJson); err != nil {
		return nil, fmt.Errorf("unmarshal: %v", err)
	}
	return apiJson, nil
}

func diffCommands(b *strings.Builder, prev, current *source.CommandJSON) {
	if prev.Title != current.Title {
		b.WriteString(fmt.Sprintf("Title changed from %q to %q\n", prev.Title, current.Title))
	}
	if prev.Doc != current.Doc {
		b.WriteString(fmt.Sprintf("Documentation changed from %q to %q\n", prev.Doc, current.Doc))
	}
	if prev.ArgDoc != current.ArgDoc {
		b.WriteString("Arguments changed from " + formatBlock(prev.ArgDoc) + " to " + formatBlock(current.ArgDoc))
	}
	if prev.ResultDoc != current.ResultDoc {
		b.WriteString("Results changed from " + formatBlock(prev.ResultDoc) + " to " + formatBlock(current.ResultDoc))
	}
}

func diffAnalyzers(b *strings.Builder, previous, current *source.AnalyzerJSON) {
	b.WriteString(fmt.Sprintf("Changes to analyzer %s:\n\n", current.Name))
	if previous.Doc != current.Doc {
		b.WriteString(fmt.Sprintf("Documentation changed from %q to %q\n", previous.Doc, current.Doc))
	}
	if previous.Default != current.Default {
		b.WriteString(fmt.Sprintf("Default changed from %v to %v\n", previous.Default, current.Default))
	}
}

func diffLenses(b *strings.Builder, previous, current *source.LensJSON) {
	b.WriteString(fmt.Sprintf("Changes to code lens %s:\n\n", current.Title))
	if previous.Title != current.Title {
		b.WriteString(fmt.Sprintf("Title changed from %q to %q\n", previous.Title, current.Title))
	}
	if previous.Doc != current.Doc {
		b.WriteString(fmt.Sprintf("Documentation changed from %q to %q\n", previous.Doc, current.Doc))
	}
}

func diffOptions(b *strings.Builder, previous, current *source.OptionJSON) {
	b.WriteString(fmt.Sprintf("Changes to option %s:\n\n", current.Name))
	if previous.Doc != current.Doc {
		diff := diffStr(previous.Doc, current.Doc)
		fmt.Fprintf(b, "Documentation changed:\n%s\n", diff)
	}
	if previous.Default != current.Default {
		b.WriteString(fmt.Sprintf("Default changed from %q to %q\n", previous.Default, current.Default))
	}
	if previous.Hierarchy != current.Hierarchy {
		b.WriteString(fmt.Sprintf("Categorization changed from %q to %q\n", previous.Hierarchy, current.Hierarchy))
	}
	if previous.Status != current.Status {
		b.WriteString(fmt.Sprintf("Status changed from %q to %q\n", previous.Status, current.Status))
	}
	if previous.Type != current.Type {
		b.WriteString(fmt.Sprintf("Type changed from %q to %q\n", previous.Type, current.Type))
	}
	// TODO(rstambler): Handle possibility of same number but different keys/values.
	if len(previous.EnumKeys.Keys) != len(current.EnumKeys.Keys) {
		b.WriteString(fmt.Sprintf("Enum keys changed from\n%s\n to \n%s\n", previous.EnumKeys, current.EnumKeys))
	}
	if len(previous.EnumValues) != len(current.EnumValues) {
		b.WriteString(fmt.Sprintf("Enum values changed from\n%s\n to \n%s\n", previous.EnumValues, current.EnumValues))
	}
}

func formatBlock(str string) string {
	if str == "" {
		return `""`
	}
	return "\n```\n" + str + "\n```\n"
}

func diffStr(before, after string) string {
	if before == after {
		return ""
	}
	// Add newlines to avoid newline messages in diff.
	unified := diffpkg.Unified("previous", "current", before+"\n", after+"\n")
	return fmt.Sprintf("%q", unified)
}
<commit_msg>gopls/api-diff: simplify the api-diff implementation<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.

//go:build go1.18
// +build go1.18

package main

import (
	"bytes"
	"context"
	"encoding/json"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"

	"github.com/google/go-cmp/cmp"
	"golang.org/x/tools/gopls/internal/lsp/source"
)

const usage = `api-diff <previous version> [<current version>]

Compare the API of two gopls versions. If the second argument is provided, it
will be used as the new version to compare against. Otherwise, compare against
the current API.
`

func main() {
	flag.Parse()

	if flag.NArg() < 1 || flag.NArg() > 2 {
		fmt.Fprint(os.Stderr, usage)
		os.Exit(2)
	}

	oldVer := flag.Arg(0)
	newVer := ""
	if flag.NArg() == 2 {
		newVer = flag.Arg(1)
	}

	apiDiff, err := diffAPI(oldVer, newVer)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("\n" + apiDiff)
}

func diffAPI(oldVer, newVer string) (string, error) {
	ctx := context.Background()
	previousAPI, err := loadAPI(ctx, oldVer)
	if err != nil {
		return "", fmt.Errorf("loading %s: %v", oldVer, err)
	}
	var currentAPI *source.APIJSON
	if newVer == "" {
		currentAPI = source.GeneratedAPIJSON
	} else {
		var err error
		currentAPI, err = loadAPI(ctx, newVer)
		if err != nil {
			return "", fmt.Errorf("loading %s: %v", newVer, err)
		}
	}

	return cmp.Diff(previousAPI, currentAPI), nil
}

func loadAPI(ctx context.Context, version string) (*source.APIJSON, error) {
	ver := fmt.Sprintf("golang.org/x/tools/gopls@%s", version)
	cmd := exec.Command("go", "run", ver, "api-json")

	stdout := &bytes.Buffer{}
	stderr := &bytes.Buffer{}
	cmd.Stdout = stdout
	cmd.Stderr = stderr

	if err := cmd.Run(); err != nil {
		return nil, fmt.Errorf("go run failed: %v; stderr:\n%s", err, stderr)
	}
	apiJson := &source.APIJSON{}
	if err := json.Unmarshal(stdout.Bytes(), apiJson); err != nil {
		return nil, fmt.Errorf("unmarshal: %v", err)
	}
	return apiJson, nil
}
<|endoftext|>


<commit_before>// Copyright 2018 The etcd Authors
//
// 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.

// etcd-tester is a program that runs functional-tester client.
package main

import (
	"flag"

	"github.com/coreos/etcd/tools/functional-tester/tester"

	"go.uber.org/zap"
)

var logger *zap.Logger

func init() {
	var err error
	logger, err = zap.NewProduction()
	if err != nil {
		panic(err)
	}
}

func main() {
	config := flag.String("config", "", "path to tester configuration")
	flag.Parse()

	defer logger.Sync()

	clus, err := tester.NewCluster(logger, *config)
	if err != nil {
		logger.Fatal("failed to create a cluster", zap.Error(err))
	}

	err = clus.Bootstrap()
	if err != nil {
		logger.Fatal("Bootstrap failed", zap.Error(err))
	}
	defer clus.DestroyEtcdAgents()

	err = clus.WaitHealth()
	if err != nil {
		logger.Fatal("WaitHealth failed", zap.Error(err))
	}

	clus.StartTester()
}
<commit_msg>functional-tester/cmd/etcd-tester: add wait health logging<commit_after>// Copyright 2018 The etcd Authors
//
// 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.

// etcd-tester is a program that runs functional-tester client.
package main

import (
	"flag"

	"github.com/coreos/etcd/tools/functional-tester/tester"

	"go.uber.org/zap"
)

var logger *zap.Logger

func init() {
	var err error
	logger, err = zap.NewProduction()
	if err != nil {
		panic(err)
	}
}

func main() {
	config := flag.String("config", "", "path to tester configuration")
	flag.Parse()

	defer logger.Sync()

	clus, err := tester.NewCluster(logger, *config)
	if err != nil {
		logger.Fatal("failed to create a cluster", zap.Error(err))
	}

	err = clus.Bootstrap()
	if err != nil {
		logger.Fatal("Bootstrap failed", zap.Error(err))
	}
	defer clus.DestroyEtcdAgents()

	logger.Info("wait health after bootstrap")
	err = clus.WaitHealth()
	if err != nil {
		logger.Fatal("WaitHealth failed", zap.Error(err))
	}

	clus.StartTester()
}
<|endoftext|>


<commit_before>// +build linux

package btrfs

/*
#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <errno.h>
#include <sys/types.h>
#include <dirent.h>
#include <linux/btrfs.h>

*/
import "C"
import (
	"fmt"
	"github.com/dotcloud/docker/graphdriver"
	"os"
	"path"
	"syscall"
	"unsafe"
)

func init() {
	graphdriver.Register("btrfs", Init)
}

func Init(home string) (graphdriver.Driver, error) {
	rootdir := path.Dir(home)

	var buf syscall.Statfs_t
	if err := syscall.Statfs(rootdir, &buf); err != nil {
		return nil, err
	}

	if buf.Type != 0x9123683E {
		return nil, fmt.Errorf("%s is not a btrfs filesystem", rootdir)
	}

	return &Driver{
		home: home,
	}, nil
}

type Driver struct {
	home string
}

func (d *Driver) String() string {
	return "btrfs"
}

func (d *Driver) Status() [][2]string {
	return nil
}

func (d *Driver) Cleanup() error {
	return nil
}

func free(p *C.char) {
	C.free(unsafe.Pointer(p))
}

func openDir(path string) (*C.DIR, error) {
	Cpath := C.CString(path)
	defer free(Cpath)

	dir := C.opendir(Cpath)
	if dir == nil {
		return nil, fmt.Errorf("Can't open dir")
	}
	return dir, nil
}

func closeDir(dir *C.DIR) {
	if dir != nil {
		C.closedir(dir)
	}
}

func getDirFd(dir *C.DIR) uintptr {
	return uintptr(C.dirfd(dir))
}

func subvolCreate(path, name string) error {
	dir, err := openDir(path)
	if err != nil {
		return err
	}
	defer closeDir(dir)

	var args C.struct_btrfs_ioctl_vol_args
	for i, c := range []byte(name) {
		args.name[i] = C.char(c)
	}

	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(dir), C.BTRFS_IOC_SUBVOL_CREATE,
		uintptr(unsafe.Pointer(&args)))
	if errno != 0 {
		return fmt.Errorf("Can't create subvolume")
	}
	return nil
}

func subvolSnapshot(src, dest, name string) error {
	srcDir, err := openDir(src)
	if err != nil {
		return err
	}
	defer closeDir(srcDir)

	destDir, err := openDir(dest)
	if err != nil {
		return err
	}
	defer closeDir(destDir)

	var args C.struct_btrfs_ioctl_vol_args_v2
	args.fd = C.__s64(getDirFd(srcDir))
	for i, c := range []byte(name) {
		args.name[i] = C.char(c)
	}

	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(destDir), C.BTRFS_IOC_SNAP_CREATE_V2,
		uintptr(unsafe.Pointer(&args)))
	if errno != 0 {
		return fmt.Errorf("Can't create subvolume")
	}
	return nil
}

func subvolDelete(path, name string) error {
	dir, err := openDir(path)
	if err != nil {
		return err
	}
	defer closeDir(dir)

	var args C.struct_btrfs_ioctl_vol_args
	for i, c := range []byte(name) {
		args.name[i] = C.char(c)
	}

	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(dir), C.BTRFS_IOC_SNAP_DESTROY,
		uintptr(unsafe.Pointer(&args)))
	if errno != 0 {
		return fmt.Errorf("Can't create subvolume")
	}
	return nil
}

func (d *Driver) subvolumesDir() string {
	return path.Join(d.home, "subvolumes")
}

func (d *Driver) subvolumesDirId(id string) string {
	return path.Join(d.subvolumesDir(), id)
}

func (d *Driver) Create(id string, parent string) error {
	subvolumes := path.Join(d.home, "subvolumes")
	if err := os.MkdirAll(subvolumes, 0700); err != nil {
		return err
	}
	if parent == "" {
		if err := subvolCreate(subvolumes, id); err != nil {
			return err
		}
	} else {
		parentDir, err := d.Get(parent)
		if err != nil {
			return err
		}
		if err := subvolSnapshot(parentDir, subvolumes, id); err != nil {
			return err
		}
	}
	return nil
}

func (d *Driver) Remove(id string) error {
	dir := d.subvolumesDirId(id)
	if _, err := os.Stat(dir); err != nil {
		return err
	}
	if err := subvolDelete(d.subvolumesDir(), id); err != nil {
		return err
	}
	return os.RemoveAll(dir)
}

func (d *Driver) Get(id string) (string, error) {
	dir := d.subvolumesDirId(id)
	st, err := os.Stat(dir)
	if err != nil {
		return "", err
	}

	if !st.IsDir() {
		return "", fmt.Errorf("%s: not a directory", dir)
	}

	return dir, nil
}

func (d *Driver) Put(id string) {
}

func (d *Driver) Exists(id string) bool {
	dir := d.subvolumesDirId(id)
	_, err := os.Stat(dir)
	return err == nil
}
<commit_msg>btrfs: Add comment to Put()<commit_after>// +build linux

package btrfs

/*
#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <errno.h>
#include <sys/types.h>
#include <dirent.h>
#include <linux/btrfs.h>

*/
import "C"
import (
	"fmt"
	"github.com/dotcloud/docker/graphdriver"
	"os"
	"path"
	"syscall"
	"unsafe"
)

func init() {
	graphdriver.Register("btrfs", Init)
}

func Init(home string) (graphdriver.Driver, error) {
	rootdir := path.Dir(home)

	var buf syscall.Statfs_t
	if err := syscall.Statfs(rootdir, &buf); err != nil {
		return nil, err
	}

	if buf.Type != 0x9123683E {
		return nil, fmt.Errorf("%s is not a btrfs filesystem", rootdir)
	}

	return &Driver{
		home: home,
	}, nil
}

type Driver struct {
	home string
}

func (d *Driver) String() string {
	return "btrfs"
}

func (d *Driver) Status() [][2]string {
	return nil
}

func (d *Driver) Cleanup() error {
	return nil
}

func free(p *C.char) {
	C.free(unsafe.Pointer(p))
}

func openDir(path string) (*C.DIR, error) {
	Cpath := C.CString(path)
	defer free(Cpath)

	dir := C.opendir(Cpath)
	if dir == nil {
		return nil, fmt.Errorf("Can't open dir")
	}
	return dir, nil
}

func closeDir(dir *C.DIR) {
	if dir != nil {
		C.closedir(dir)
	}
}

func getDirFd(dir *C.DIR) uintptr {
	return uintptr(C.dirfd(dir))
}

func subvolCreate(path, name string) error {
	dir, err := openDir(path)
	if err != nil {
		return err
	}
	defer closeDir(dir)

	var args C.struct_btrfs_ioctl_vol_args
	for i, c := range []byte(name) {
		args.name[i] = C.char(c)
	}

	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(dir), C.BTRFS_IOC_SUBVOL_CREATE,
		uintptr(unsafe.Pointer(&args)))
	if errno != 0 {
		return fmt.Errorf("Can't create subvolume")
	}
	return nil
}

func subvolSnapshot(src, dest, name string) error {
	srcDir, err := openDir(src)
	if err != nil {
		return err
	}
	defer closeDir(srcDir)

	destDir, err := openDir(dest)
	if err != nil {
		return err
	}
	defer closeDir(destDir)

	var args C.struct_btrfs_ioctl_vol_args_v2
	args.fd = C.__s64(getDirFd(srcDir))
	for i, c := range []byte(name) {
		args.name[i] = C.char(c)
	}

	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(destDir), C.BTRFS_IOC_SNAP_CREATE_V2,
		uintptr(unsafe.Pointer(&args)))
	if errno != 0 {
		return fmt.Errorf("Can't create subvolume")
	}
	return nil
}

func subvolDelete(path, name string) error {
	dir, err := openDir(path)
	if err != nil {
		return err
	}
	defer closeDir(dir)

	var args C.struct_btrfs_ioctl_vol_args
	for i, c := range []byte(name) {
		args.name[i] = C.char(c)
	}

	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(dir), C.BTRFS_IOC_SNAP_DESTROY,
		uintptr(unsafe.Pointer(&args)))
	if errno != 0 {
		return fmt.Errorf("Can't create subvolume")
	}
	return nil
}

func (d *Driver) subvolumesDir() string {
	return path.Join(d.home, "subvolumes")
}

func (d *Driver) subvolumesDirId(id string) string {
	return path.Join(d.subvolumesDir(), id)
}

func (d *Driver) Create(id string, parent string) error {
	subvolumes := path.Join(d.home, "subvolumes")
	if err := os.MkdirAll(subvolumes, 0700); err != nil {
		return err
	}
	if parent == "" {
		if err := subvolCreate(subvolumes, id); err != nil {
			return err
		}
	} else {
		parentDir, err := d.Get(parent)
		if err != nil {
			return err
		}
		if err := subvolSnapshot(parentDir, subvolumes, id); err != nil {
			return err
		}
	}
	return nil
}

func (d *Driver) Remove(id string) error {
	dir := d.subvolumesDirId(id)
	if _, err := os.Stat(dir); err != nil {
		return err
	}
	if err := subvolDelete(d.subvolumesDir(), id); err != nil {
		return err
	}
	return os.RemoveAll(dir)
}

func (d *Driver) Get(id string) (string, error) {
	dir := d.subvolumesDirId(id)
	st, err := os.Stat(dir)
	if err != nil {
		return "", err
	}

	if !st.IsDir() {
		return "", fmt.Errorf("%s: not a directory", dir)
	}

	return dir, nil
}

func (d *Driver) Put(id string) {
	// Get() creates no runtime resources (like e.g. mounts)
	// so this doesn't need to do anything.
}

func (d *Driver) Exists(id string) bool {
	dir := d.subvolumesDirId(id)
	_, err := os.Stat(dir)
	return err == nil
}
<|endoftext|>


<commit_before>// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

// +build appengine

package mysql

import (
	"appengine/cloudsql"
)

func init() {
	RegisterDial("cloudsql", cloudsql.Dial)
}
<commit_msg>suing correct mysql driver<commit_after>// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
//
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.

// +build appengine

package mysql

import (
	"google.golang.org/appengine/cloudsql"
)

func init() {
	RegisterDial("cloudsql", cloudsql.Dial)
}
<|endoftext|>


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

package dns

import (
	"crypto/sha1"
	"hash"
	"io"
	"strings"
)

type saltWireFmt struct {
	Salt string `dns:"size-hex"`
}

// HashName hashes a string (label) according to RFC 5155. It returns the hashed string.
func HashName(label string, ha uint8, iter uint16, salt string) string {
	saltwire := new(saltWireFmt)
	saltwire.Salt = salt
	wire := make([]byte, DefaultMsgSize)
	n, err := PackStruct(saltwire, wire, 0)
	if err != nil {
		return ""
	}
	wire = wire[:n]
	name := make([]byte, 255)
	off, err := PackDomainName(strings.ToLower(label), name, 0, nil, false)
	if err != nil {
		return ""
	}
	name = name[:off]
	var s hash.Hash
	switch ha {
	case SHA1:
		s = sha1.New()
	default:
		return ""
	}

	// k = 0
	name = append(name, wire...)
	io.WriteString(s, string(name))
	nsec3 := s.Sum(nil)
	// k > 0
	for k := uint16(0); k < iter; k++ {
		s.Reset()
		nsec3 = append(nsec3, wire...)
		io.WriteString(s, string(nsec3))
		nsec3 = s.Sum(nil)
	}
	return unpackBase32(nsec3)
}

// Implement the HashNames method of Denialer
func (rr *NSEC3) HashNames(domain string) {
	rr.Header().Name = strings.ToLower(HashName(rr.Header().Name, rr.Hash, rr.Iterations, rr.Salt)) + "." + domain
	rr.NextDomain = HashName(rr.NextDomain, rr.Hash, rr.Iterations, rr.Salt)
}

// Implement the Match method of Denialer
func (rr *NSEC3) Match(domain string) bool {
	return strings.ToUpper(SplitDomainName(rr.Header().Name)[0]) == strings.ToUpper(HashName(domain, rr.Hash, rr.Iterations, rr.Salt))
}

// Implement the Match method of Denialer
func (rr *NSEC) Match(domain string) bool {
	return strings.ToUpper(rr.Header().Name) == strings.ToUpper(domain)
}

func (rr *NSEC3) MatchType(rrtype uint16) bool {
	for _, t := range rr.TypeBitMap {
		if t == rrtype {
			return true
		}
		if t > rrtype {
			return false
		}
	}
	return false
}

func (rr *NSEC) MatchType(rrtype uint16) bool {
	for _, t := range rr.TypeBitMap {
		if t == rrtype {
			return true
		}
		if t > rrtype {
			return false
		}
	}
	return false
}

// Cover checks if domain is covered by the NSEC3 record. Domain must be given in plain text (i.e. not hashed)
// TODO(mg): this doesn't loop around
// TODO(mg): make a CoverHashed variant?
func (rr *NSEC3) Cover(domain string) bool {
	hashdom := strings.ToUpper(HashName(domain, rr.Hash, rr.Iterations, rr.Salt))
	nextdom := strings.ToUpper(rr.NextDomain)
	owner := strings.ToUpper(SplitDomainName(rr.Header().Name)[0])                                                                     // The hashed part
	apex := strings.ToUpper(HashName(strings.Join(SplitDomainName(rr.Header().Name)[1:], "."), rr.Hash, rr.Iterations, rr.Salt)) + "." // The name of the zone
	// if nextdomain equals the apex, it is considered The End. So in that case hashdom is always less then nextdomain
	if hashdom > owner && nextdom == apex {
		return true
	}

	if hashdom > owner && hashdom <= nextdom {
		return true
	}

	return false
}

// Cover checks if domain is covered by the NSEC record. Domain must be given in plain text.
func (rr *NSEC) Cover(domain string) bool {
	return false
}
<commit_msg>Clean up the nsecx file<commit_after>// Copyright 2011 Miek Gieben. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package dns

import (
	"crypto/sha1"
	"hash"
	"io"
	"strings"
)

type saltWireFmt struct {
	Salt string `dns:"size-hex"`
}

// HashName hashes a string (label) according to RFC 5155. It returns the hashed string.
func HashName(label string, ha uint8, iter uint16, salt string) string {
	saltwire := new(saltWireFmt)
	saltwire.Salt = salt
	wire := make([]byte, DefaultMsgSize)
	n, err := PackStruct(saltwire, wire, 0)
	if err != nil {
		return ""
	}
	wire = wire[:n]
	name := make([]byte, 255)
	off, err := PackDomainName(strings.ToLower(label), name, 0, nil, false)
	if err != nil {
		return ""
	}
	name = name[:off]
	var s hash.Hash
	switch ha {
	case SHA1:
		s = sha1.New()
	default:
		return ""
	}

	// k = 0
	name = append(name, wire...)
	io.WriteString(s, string(name))
	nsec3 := s.Sum(nil)
	// k > 0
	for k := uint16(0); k < iter; k++ {
		s.Reset()
		nsec3 = append(nsec3, wire...)
		io.WriteString(s, string(nsec3))
		nsec3 = s.Sum(nil)
	}
	return unpackBase32(nsec3)
}
<|endoftext|>


<commit_before>package ciolite

// Api functions that support: https://context.io/docs/lite/users/webhooks

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/mail"
)

// GetUsersWebhooksResponse data struct
// 	https://context.io/docs/lite/users/webhooks#get
// 	https://context.io/docs/lite/users/webhooks#id-get
type GetUsersWebhooksResponse struct {
	CallbackURL        string `json:"callback_url,omitempty"`
	FailureNotifURL    string `json:"failure_notif_url,omitempty"`
	WebhookID          string `json:"webhook_id,omitempty"`
	FilterTo           string `json:"filter_to,omitempty"`
	FilterFrom         string `json:"filter_from,omitempty"`
	FilterCc           string `json:"filter_cc,omitempty"`
	FilterSubject      string `json:"filter_subject,omitempty"`
	FilterThread       string `json:"filter_thread,omitempty"`
	FilterNewImportant string `json:"filter_new_important,omitempty"`
	FilterFileName     string `json:"filter_file_name,omitempty"`
	FilterFolderAdded  string `json:"filter_folder_added,omitempty"`
	FilterToDomain     string `json:"filter_to_domain,omitempty"`
	FilterFromDomain   string `json:"filter_from_domain,omitempty"`
	BodyType           string `json:"body_type,omitempty"`
	ResourceURL        string `json:"resource_url,omitempty"`

	Active            bool `json:"active,omitempty"`
	Failure           bool `json:"failure,omitempty"`
	IncludeBody       bool `json:"include_body,omitempty"`
	IncludeHeader     bool `json:"include_header,omitempty"`
	ReceiveDrafts     bool `json:"receive_drafts,omitempty"`
	ReceiveAllChanges bool `json:"receive_all_changes,omitempty"`
	ReceiveHistorical bool `json:"receive_historical,omitempty"`
}

// CreateUserWebhookParams form values data struct.
// Requires: CallbackURL, FailureNotifUrl, and may optionally contain
// FilterTo, FilterFrom, FilterCC, FilterSubject, FilterThread,
// FilterNewImportant, FilterFileName, FilterFolderAdded, FilterToDomain,
// FilterFromDomain, IncludeBody, BodyType
// 	https://context.io/docs/lite/users/webhooks#post
type CreateUserWebhookParams struct {
	// Requires:
	CallbackURL     string `json:"callback_url"`
	FailureNotifURL string `json:"failure_notif_url"`

	// Optional:
	FilterTo           string `json:"filter_to,omitempty"`
	FilterFrom         string `json:"filter_from,omitempty"`
	FilterCC           string `json:"filter_cc,omitempty"`
	FilterSubject      string `json:"filter_subject,omitempty"`
	FilterThread       string `json:"filter_thread,omitempty"`
	FilterNewImportant string `json:"filter_new_important,omitempty"`
	FilterFileName     string `json:"filter_file_name,omitempty"`
	FilterFolderAdded  string `json:"filter_folder_added,omitempty"`
	FilterToDomain     string `json:"filter_to_domain,omitempty"`
	FilterFromDomain   string `json:"filter_from_domain,omitempty"`
	BodyType           string `json:"body_type,omitempty"`
	IncludeBody        bool   `json:"include_body,omitempty"`
	IncludeHeader      bool   `json:"include_header,omitempty"`
	ReceiveDrafts      bool   `json:"receive_drafts,omitempty"`
	ReceiveAllChanges  bool   `json:"receive_all_changes,omitempty"`
	ReceiveHistorical  bool   `json:"receive_historical,omitempty"`
}

// CreateUserWebhookResponse data struct
// 	https://context.io/docs/lite/users/webhooks#post
type CreateUserWebhookResponse struct {
	WebhookID   string `json:"webhook_id,omitempty"`
	ResourceURL string `json:"resource_url,omitempty"`

	Success bool `json:"success,omitempty"`
}

// ModifyUserWebhookParams form values data struct.
// formValues requires Active
// 	https://context.io/docs/lite/users/webhooks#id-post
type ModifyUserWebhookParams struct {
	// Required:
	Active bool `json:"active"`
}

// ModifyWebhookResponse data struct
// 	https://context.io/docs/lite/users/webhooks#id-post
type ModifyWebhookResponse struct {
	ResourceURL string `json:"resource_url,omitempty"`

	Success bool `json:"success,omitempty"`
}

// DeleteWebhookResponse data struct
// 	https://context.io/docs/lite/users/webhooks#id-delete
type DeleteWebhookResponse struct {
	Success bool `json:"success,omitempty"`
}

// WebhookCallback data struct that will be received from CIO
// 	https://context.io/docs/lite/users/webhooks#callbacks
type WebhookCallback struct {
	AccountID string `json:"account_id,omitempty"`
	WebhookID string `json:"webhook_id,omitempty"`
	Token     string `json:"token,omitempty" valid:"required"`
	Signature string `json:"signature,omitempty" valid:"required"`

	Timestamp int `json:"timestamp,omitempty" valid:"required"`

	// Data is an error message that gives more information about the cause of failure
	Data string `json:"data,omitempty"`

	MessageData WebhookMessageData `json:"message_data,omitempty"`
}

// WebhookMessageData data struct within WebhookCallback
// 	https://context.io/docs/lite/users/webhooks#callbacks
type WebhookMessageData struct {
	MessageID      string `json:"message_id,omitempty"`
	EmailMessageID string `json:"email_message_id,omitempty"`
	Subject        string `json:"subject,omitempty"`

	References []string `json:"references,omitempty"`
	Folders    []string `json:"folders,omitempty"`

	Date         int `json:"date,omitempty"`
	DateReceived int `json:"date_received,omitempty"`

	ID uint64 `json:"id,omitempty"` // Unique message identifier or body hash

	Addresses WebhookMessageDataAddresses `json:"addresses,omitempty"`

	PersonInfo PersonInfo `json:"person_info,omitempty"`

	Flags WebhookMessageDataFlags `json:"flags,omitempty"`

	Sources []WebhookMessageDataAccount `json:"sources,omitempty"`

	EmailAccounts []WebhookMessageDataAccount `json:"email_accounts,omitempty"`

	Files []WebhookMessageDataFile `json:"files,omitempty"`

	Bodies []WebhookBody `json:"bodies,omitempty"`

	Headers mail.Header `json:"headers,omitempty"`
}

// WebhookBody embedded data struct within WebhookMessageData
// 	https://context.io/docs/lite/users/webhooks#callbacks
type WebhookBody struct {
	Type        string `json:"type,omitempty"`
	Charset     string `json:"charset,omitempty"`
	BodySection string `json:"body_section,omitempty"`
	Content     string `json:"content,omitempty"`
}

// WebhookMessageDataFlags embedded data struct within WebhookMessageData
// 	https://context.io/docs/lite/users/webhooks#callbacks
type WebhookMessageDataFlags struct {
	Flagged  bool `json:"flagged,omitempty"`
	Answered bool `json:"answered,omitempty"`
	Draft    bool `json:"draft,omitempty"`
	Seen     bool `json:"seen,omitempty"`
}

// WebhookMessageDataAccount embedded data struct within WebhookMessageData
// 	https://context.io/docs/lite/users/webhooks#callbacks
type WebhookMessageDataAccount struct {
	Label       string `json:"label,omitempty"`
	Folder      string `json:"folder,omitempty"`
	UID         int    `json:"uid,omitempty"`
	ResourceURL string `json:"resource_url,omitempty"`
}

// WebhookMessageDataFile embedded data struct within WebhookMessageData
// 	https://context.io/docs/lite/users/webhooks#callbacks
type WebhookMessageDataFile struct {
	ContentID          string `json:"content_id,omitempty"`
	Type               string `json:"type,omitempty"`
	FileName           string `json:"file_name,omitempty"`
	BodySection        string `json:"body_section,omitempty"`
	ContentDisposition string `json:"content_disposition,omitempty"`
	MainFileName       string `json:"main_file_name,omitempty"`

	XAttachmentID interface{} `json:"x_attachment_id,omitempty"` // appears to be a single string and also an array of strings

	FileNameStructure [][]string `json:"file_name_structure,omitempty"`

	AttachmentID int `json:"attachment_id,omitempty"`
	Size         int `json:"size,omitempty"`

	IsEmbedded bool `json:"is_embedded,omitempty"`
}

// WebhookMessageDataAddresses struct within WebhookMessageData
// 	https://context.io/docs/lite/users/webhooks#callbacks
type WebhookMessageDataAddresses struct {
	From       Address   `json:"from,omitempty"`
	To         []Address `json:"to,omitempty"`
	Cc         []Address `json:"cc,omitempty"`
	Bcc        []Address `json:"bcc,omitempty"`
	Sender     []Address `json:"sender,omitempty"`
	ReplyTo    []Address `json:"reply_to,omitempty"`
	ReturnPath []Address `json:"return_path,omitempty"`
}

// UnmarshalJSON is here because the empty state is an array in the json, and is a object/map when populated
func (m *WebhookMessageDataAddresses) UnmarshalJSON(b []byte) error {
	if bytes.Equal([]byte(`[]`), b) {
		// its the empty array, set an empty struct
		*m = WebhookMessageDataAddresses{}
		return nil
	}
	// avoid recursion
	type webhookMessageDataAddressesTemp WebhookMessageDataAddresses
	var tmp webhookMessageDataAddressesTemp

	if err := json.Unmarshal(b, &tmp); err != nil {
		return err
	}
	*m = WebhookMessageDataAddresses(tmp)
	return nil
}

// GetUserWebhooks gets listings of Webhooks configured for a user.
// 	https://context.io/docs/lite/users/webhooks#get
func (cioLite CioLite) GetUserWebhooks(userID string) ([]GetUsersWebhooksResponse, error) {

	// Make request
	request := clientRequest{
		Method: "GET",
		Path:   fmt.Sprintf("/lite/users/%s/webhooks", userID),
		UserID: userID,
	}

	// Make response
	var response []GetUsersWebhooksResponse

	// Request
	err := cioLite.doFormRequest(request, &response)

	return response, err
}

// GetUserWebhook gets the properties of a given Webhook.
// 	https://context.io/docs/lite/users/webhooks#id-get
func (cioLite CioLite) GetUserWebhook(userID string, webhookID string) (GetUsersWebhooksResponse, error) {

	// Make request
	request := clientRequest{
		Method: "GET",
		Path:   fmt.Sprintf("/lite/users/%s/webhooks/%s", userID, webhookID),
		UserID: userID,
	}

	// Make response
	var response GetUsersWebhooksResponse

	// Request
	err := cioLite.doFormRequest(request, &response)

	return response, err
}

// CreateUserWebhook creates a new Webhook on a user.
// formValues requires CallbackURL, FailureNotifUrl, and may optionally contain
// FilterTo, FilterFrom, FilterCC, FilterSubject, FilterThread,
// FilterNewImportant, FilterFileName, FilterFolderAdded, FilterToDomain,
// FilterFromDomain, IncludeBody, BodyType
// 	https://context.io/docs/lite/users/webhooks#post
func (cioLite CioLite) CreateUserWebhook(userID string, formValues CreateUserWebhookParams) (CreateUserWebhookResponse, error) {

	// Make request
	request := clientRequest{
		Method:     "POST",
		Path:       fmt.Sprintf("/lite/users/%s/webhooks", userID),
		FormValues: formValues,
		UserID:     userID,
	}

	// Make response
	var response CreateUserWebhookResponse

	// Request
	err := cioLite.doFormRequest(request, &response)

	return response, err
}

// ModifyUserWebhook changes the properties of a given Webhook.
// formValues requires Active
// 	https://context.io/docs/lite/users/webhooks#id-post
func (cioLite CioLite) ModifyUserWebhook(userID string, webhookID string, formValues ModifyUserWebhookParams) (ModifyWebhookResponse, error) {

	// Make request
	request := clientRequest{
		Method:     "POST",
		Path:       fmt.Sprintf("/lite/users/%s/webhooks/%s", userID, webhookID),
		FormValues: formValues,
		UserID:     userID,
	}

	// Make response
	var response ModifyWebhookResponse

	// Request
	err := cioLite.doFormRequest(request, &response)

	return response, err
}

// DeleteUserWebhookAccount cancels a Webhook.
// 	https://context.io/docs/lite/users/webhooks#id-delete
func (cioLite CioLite) DeleteUserWebhookAccount(userID string, webhookID string) (DeleteWebhookResponse, error) {

	// Make request
	request := clientRequest{
		Method: "DELETE",
		Path:   fmt.Sprintf("/lite/users/%s/webhooks/%s", userID, webhookID),
		UserID: userID,
	}

	// Make response
	var response DeleteWebhookResponse

	// Request
	err := cioLite.doFormRequest(request, &response)

	return response, err
}
<commit_msg>remove param that totally isn't real<commit_after>package ciolite

// Api functions that support: https://context.io/docs/lite/users/webhooks

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/mail"
)

// GetUsersWebhooksResponse data struct
// 	https://context.io/docs/lite/users/webhooks#get
// 	https://context.io/docs/lite/users/webhooks#id-get
type GetUsersWebhooksResponse struct {
	CallbackURL        string `json:"callback_url,omitempty"`
	WebhookID          string `json:"webhook_id,omitempty"`
	FilterTo           string `json:"filter_to,omitempty"`
	FilterFrom         string `json:"filter_from,omitempty"`
	FilterCc           string `json:"filter_cc,omitempty"`
	FilterSubject      string `json:"filter_subject,omitempty"`
	FilterThread       string `json:"filter_thread,omitempty"`
	FilterNewImportant string `json:"filter_new_important,omitempty"`
	FilterFileName     string `json:"filter_file_name,omitempty"`
	FilterFolderAdded  string `json:"filter_folder_added,omitempty"`
	FilterToDomain     string `json:"filter_to_domain,omitempty"`
	FilterFromDomain   string `json:"filter_from_domain,omitempty"`
	BodyType           string `json:"body_type,omitempty"`
	ResourceURL        string `json:"resource_url,omitempty"`

	Active            bool `json:"active,omitempty"`
	Failure           bool `json:"failure,omitempty"`
	IncludeBody       bool `json:"include_body,omitempty"`
	IncludeHeader     bool `json:"include_header,omitempty"`
	ReceiveDrafts     bool `json:"receive_drafts,omitempty"`
	ReceiveAllChanges bool `json:"receive_all_changes,omitempty"`
	ReceiveHistorical bool `json:"receive_historical,omitempty"`
}

// CreateUserWebhookParams form values data struct.
// Requires: CallbackURL, FailureNotifUrl, and may optionally contain
// FilterTo, FilterFrom, FilterCC, FilterSubject, FilterThread,
// FilterNewImportant, FilterFileName, FilterFolderAdded, FilterToDomain,
// FilterFromDomain, IncludeBody, BodyType
// 	https://context.io/docs/lite/users/webhooks#post
type CreateUserWebhookParams struct {
	// Requires:
	CallbackURL string `json:"callback_url"`

	// Optional:
	FilterTo           string `json:"filter_to,omitempty"`
	FilterFrom         string `json:"filter_from,omitempty"`
	FilterCC           string `json:"filter_cc,omitempty"`
	FilterSubject      string `json:"filter_subject,omitempty"`
	FilterThread       string `json:"filter_thread,omitempty"`
	FilterNewImportant string `json:"filter_new_important,omitempty"`
	FilterFileName     string `json:"filter_file_name,omitempty"`
	FilterFolderAdded  string `json:"filter_folder_added,omitempty"`
	FilterToDomain     string `json:"filter_to_domain,omitempty"`
	FilterFromDomain   string `json:"filter_from_domain,omitempty"`
	BodyType           string `json:"body_type,omitempty"`
	IncludeBody        bool   `json:"include_body,omitempty"`
	IncludeHeader      bool   `json:"include_header,omitempty"`
	ReceiveDrafts      bool   `json:"receive_drafts,omitempty"`
	ReceiveAllChanges  bool   `json:"receive_all_changes,omitempty"`
	ReceiveHistorical  bool   `json:"receive_historical,omitempty"`
}

// CreateUserWebhookResponse data struct
// 	https://context.io/docs/lite/users/webhooks#post
type CreateUserWebhookResponse struct {
	WebhookID   string `json:"webhook_id,omitempty"`
	ResourceURL string `json:"resource_url,omitempty"`

	Success bool `json:"success,omitempty"`
}

// ModifyUserWebhookParams form values data struct.
// formValues requires Active
// 	https://context.io/docs/lite/users/webhooks#id-post
type ModifyUserWebhookParams struct {
	// Required:
	Active bool `json:"active"`
}

// ModifyWebhookResponse data struct
// 	https://context.io/docs/lite/users/webhooks#id-post
type ModifyWebhookResponse struct {
	ResourceURL string `json:"resource_url,omitempty"`

	Success bool `json:"success,omitempty"`
}

// DeleteWebhookResponse data struct
// 	https://context.io/docs/lite/users/webhooks#id-delete
type DeleteWebhookResponse struct {
	Success bool `json:"success,omitempty"`
}

// WebhookCallback data struct that will be received from CIO
// 	https://context.io/docs/lite/users/webhooks#callbacks
type WebhookCallback struct {
	AccountID string `json:"account_id,omitempty"`
	WebhookID string `json:"webhook_id,omitempty"`
	Token     string `json:"token,omitempty" valid:"required"`
	Signature string `json:"signature,omitempty" valid:"required"`

	Timestamp int `json:"timestamp,omitempty" valid:"required"`

	// Data is an error message that gives more information about the cause of failure
	Data string `json:"data,omitempty"`

	MessageData WebhookMessageData `json:"message_data,omitempty"`
}

// WebhookMessageData data struct within WebhookCallback
// 	https://context.io/docs/lite/users/webhooks#callbacks
type WebhookMessageData struct {
	MessageID      string `json:"message_id,omitempty"`
	EmailMessageID string `json:"email_message_id,omitempty"`
	Subject        string `json:"subject,omitempty"`

	References []string `json:"references,omitempty"`
	Folders    []string `json:"folders,omitempty"`

	Date         int `json:"date,omitempty"`
	DateReceived int `json:"date_received,omitempty"`

	ID uint64 `json:"id,omitempty"` // Unique message identifier or body hash

	Addresses WebhookMessageDataAddresses `json:"addresses,omitempty"`

	PersonInfo PersonInfo `json:"person_info,omitempty"`

	Flags WebhookMessageDataFlags `json:"flags,omitempty"`

	Sources []WebhookMessageDataAccount `json:"sources,omitempty"`

	EmailAccounts []WebhookMessageDataAccount `json:"email_accounts,omitempty"`

	Files []WebhookMessageDataFile `json:"files,omitempty"`

	Bodies []WebhookBody `json:"bodies,omitempty"`

	Headers mail.Header `json:"headers,omitempty"`
}

// WebhookBody embedded data struct within WebhookMessageData
// 	https://context.io/docs/lite/users/webhooks#callbacks
type WebhookBody struct {
	Type        string `json:"type,omitempty"`
	Charset     string `json:"charset,omitempty"`
	BodySection string `json:"body_section,omitempty"`
	Content     string `json:"content,omitempty"`
}

// WebhookMessageDataFlags embedded data struct within WebhookMessageData
// 	https://context.io/docs/lite/users/webhooks#callbacks
type WebhookMessageDataFlags struct {
	Flagged  bool `json:"flagged,omitempty"`
	Answered bool `json:"answered,omitempty"`
	Draft    bool `json:"draft,omitempty"`
	Seen     bool `json:"seen,omitempty"`
}

// WebhookMessageDataAccount embedded data struct within WebhookMessageData
// 	https://context.io/docs/lite/users/webhooks#callbacks
type WebhookMessageDataAccount struct {
	Label       string `json:"label,omitempty"`
	Folder      string `json:"folder,omitempty"`
	UID         int    `json:"uid,omitempty"`
	ResourceURL string `json:"resource_url,omitempty"`
}

// WebhookMessageDataFile embedded data struct within WebhookMessageData
// 	https://context.io/docs/lite/users/webhooks#callbacks
type WebhookMessageDataFile struct {
	ContentID          string `json:"content_id,omitempty"`
	Type               string `json:"type,omitempty"`
	FileName           string `json:"file_name,omitempty"`
	BodySection        string `json:"body_section,omitempty"`
	ContentDisposition string `json:"content_disposition,omitempty"`
	MainFileName       string `json:"main_file_name,omitempty"`

	XAttachmentID interface{} `json:"x_attachment_id,omitempty"` // appears to be a single string and also an array of strings

	FileNameStructure [][]string `json:"file_name_structure,omitempty"`

	AttachmentID int `json:"attachment_id,omitempty"`
	Size         int `json:"size,omitempty"`

	IsEmbedded bool `json:"is_embedded,omitempty"`
}

// WebhookMessageDataAddresses struct within WebhookMessageData
// 	https://context.io/docs/lite/users/webhooks#callbacks
type WebhookMessageDataAddresses struct {
	From       Address   `json:"from,omitempty"`
	To         []Address `json:"to,omitempty"`
	Cc         []Address `json:"cc,omitempty"`
	Bcc        []Address `json:"bcc,omitempty"`
	Sender     []Address `json:"sender,omitempty"`
	ReplyTo    []Address `json:"reply_to,omitempty"`
	ReturnPath []Address `json:"return_path,omitempty"`
}

// UnmarshalJSON is here because the empty state is an array in the json, and is a object/map when populated
func (m *WebhookMessageDataAddresses) UnmarshalJSON(b []byte) error {
	if bytes.Equal([]byte(`[]`), b) {
		// its the empty array, set an empty struct
		*m = WebhookMessageDataAddresses{}
		return nil
	}
	// avoid recursion
	type webhookMessageDataAddressesTemp WebhookMessageDataAddresses
	var tmp webhookMessageDataAddressesTemp

	if err := json.Unmarshal(b, &tmp); err != nil {
		return err
	}
	*m = WebhookMessageDataAddresses(tmp)
	return nil
}

// GetUserWebhooks gets listings of Webhooks configured for a user.
// 	https://context.io/docs/lite/users/webhooks#get
func (cioLite CioLite) GetUserWebhooks(userID string) ([]GetUsersWebhooksResponse, error) {

	// Make request
	request := clientRequest{
		Method: "GET",
		Path:   fmt.Sprintf("/lite/users/%s/webhooks", userID),
		UserID: userID,
	}

	// Make response
	var response []GetUsersWebhooksResponse

	// Request
	err := cioLite.doFormRequest(request, &response)

	return response, err
}

// GetUserWebhook gets the properties of a given Webhook.
// 	https://context.io/docs/lite/users/webhooks#id-get
func (cioLite CioLite) GetUserWebhook(userID string, webhookID string) (GetUsersWebhooksResponse, error) {

	// Make request
	request := clientRequest{
		Method: "GET",
		Path:   fmt.Sprintf("/lite/users/%s/webhooks/%s", userID, webhookID),
		UserID: userID,
	}

	// Make response
	var response GetUsersWebhooksResponse

	// Request
	err := cioLite.doFormRequest(request, &response)

	return response, err
}

// CreateUserWebhook creates a new Webhook on a user.
// formValues requires CallbackURL, FailureNotifUrl, and may optionally contain
// FilterTo, FilterFrom, FilterCC, FilterSubject, FilterThread,
// FilterNewImportant, FilterFileName, FilterFolderAdded, FilterToDomain,
// FilterFromDomain, IncludeBody, BodyType
// 	https://context.io/docs/lite/users/webhooks#post
func (cioLite CioLite) CreateUserWebhook(userID string, formValues CreateUserWebhookParams) (CreateUserWebhookResponse, error) {

	// Make request
	request := clientRequest{
		Method:     "POST",
		Path:       fmt.Sprintf("/lite/users/%s/webhooks", userID),
		FormValues: formValues,
		UserID:     userID,
	}

	// Make response
	var response CreateUserWebhookResponse

	// Request
	err := cioLite.doFormRequest(request, &response)

	return response, err
}

// ModifyUserWebhook changes the properties of a given Webhook.
// formValues requires Active
// 	https://context.io/docs/lite/users/webhooks#id-post
func (cioLite CioLite) ModifyUserWebhook(userID string, webhookID string, formValues ModifyUserWebhookParams) (ModifyWebhookResponse, error) {

	// Make request
	request := clientRequest{
		Method:     "POST",
		Path:       fmt.Sprintf("/lite/users/%s/webhooks/%s", userID, webhookID),
		FormValues: formValues,
		UserID:     userID,
	}

	// Make response
	var response ModifyWebhookResponse

	// Request
	err := cioLite.doFormRequest(request, &response)

	return response, err
}

// DeleteUserWebhookAccount cancels a Webhook.
// 	https://context.io/docs/lite/users/webhooks#id-delete
func (cioLite CioLite) DeleteUserWebhookAccount(userID string, webhookID string) (DeleteWebhookResponse, error) {

	// Make request
	request := clientRequest{
		Method: "DELETE",
		Path:   fmt.Sprintf("/lite/users/%s/webhooks/%s", userID, webhookID),
		UserID: userID,
	}

	// Make response
	var response DeleteWebhookResponse

	// Request
	err := cioLite.doFormRequest(request, &response)

	return response, err
}
<|endoftext|>