<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 bigquery

import (
	"fmt"
	"net/http"
	"reflect"
	"strings"
	"testing"
	"time"

	"cloud.google.com/go/internal/testutil"
	"golang.org/x/net/context"
	"google.golang.org/api/googleapi"
	"google.golang.org/api/iterator"
	"google.golang.org/api/option"
)

func TestIntegration(t *testing.T) {
	if testing.Short() {
		t.Skip("Integration tests skipped in short mode")
	}

	ctx := context.Background()
	ts := testutil.TokenSource(ctx, Scope)
	if ts == nil {
		t.Skip("Integration tests skipped. See CONTRIBUTING.md for details")
	}

	projID := testutil.ProjID()
	c, err := NewClient(ctx, projID, option.WithTokenSource(ts))
	if err != nil {
		t.Fatal(err)
	}
	ds := c.Dataset("bigquery_integration_test")
	if err := ds.Create(ctx); err != nil && !hasStatusCode(err, http.StatusConflict) { // AlreadyExists is 409
		t.Fatal(err)
	}
	schema := Schema([]*FieldSchema{
		{Name: "name", Type: StringFieldType},
		{Name: "num", Type: IntegerFieldType},
	})
	table := ds.Table("t1")
	// Delete the table in case it already exists. (Ignore errors.)
	table.Delete(ctx)
	// Create the table.
	err = table.Create(ctx, schema, TableExpiration(time.Now().Add(5*time.Minute)))
	if err != nil {
		t.Fatal(err)
	}
	// Check table metadata.
	md, err := table.Metadata(ctx)
	if err != nil {
		t.Fatal(err)
	}
	// TODO(jba): check md more thorougly.
	if got, want := md.ID, fmt.Sprintf("%s:%s.%s", projID, ds.id, table.TableID); got != want {
		t.Errorf("metadata.ID: got %q, want %q", got, want)
	}
	if got, want := md.Type, RegularTable; got != want {
		t.Errorf("metadata.Type: got %v, want %v", got, want)
	}

	// Iterate over tables in the dataset.
	it := ds.Tables(ctx)
	var tables []*Table
	for {
		tbl, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			t.Fatal(err)
		}
		tables = append(tables, tbl)
	}
	if got, want := tables, []*Table{table}; !reflect.DeepEqual(got, want) {
		t.Errorf("Tables: got %v, want %v", got, want)
	}

	// Populate the table.
	upl := table.Uploader()
	var rows []*ValuesSaver
	for i, name := range []string{"a", "b", "c"} {
		rows = append(rows, &ValuesSaver{
			Schema:   schema,
			InsertID: name,
			Row:      []Value{name, i},
		})
	}
	if err := upl.Put(ctx, rows); err != nil {
		t.Fatal(err)
	}

	checkRead := func(it *RowIterator) {
		for i := 0; true; i++ {
			var vals ValueList
			err := it.Next(&vals)
			if err == iterator.Done {
				break
			}
			if err != nil {
				t.Fatal(err)
			}
			if got, want := vals, rows[i].Row; !reflect.DeepEqual([]Value(got), want) {
				t.Errorf("got %v, want %v", got, want)
			}
		}
	}
	// Read the table.
	checkRead(table.Read(ctx))

	// Query the table.
	q := c.Query("select name, num from t1")
	q.DefaultProjectID = projID
	q.DefaultDatasetID = ds.id

	rit, err := q.Read(ctx)
	if err != nil {
		t.Fatal(err)
	}
	checkRead(rit)

	// Query the long way.
	job1, err := q.Run(ctx)
	if err != nil {
		t.Fatal(err)
	}
	job2, err := c.JobFromID(ctx, job1.ID())
	if err != nil {
		t.Fatal(err)
	}
	// TODO(jba): poll status until job is done
	_, err = job2.Status(ctx)
	if err != nil {
		t.Fatal(err)
	}

	rit, err = job2.Read(ctx)
	if err != nil {
		t.Fatal(err)
	}
	checkRead(rit)

	// Test Update.
	tm, err := table.Metadata(ctx)
	if err != nil {
		t.Fatal(err)
	}
	wantDescription := tm.Description + "more"
	wantName := tm.Name + "more"
	got, err := table.Update(ctx, TableMetadataToUpdate{
		Description: wantDescription,
		Name:        wantName,
	})
	if err != nil {
		t.Fatal(err)
	}
	if got.Description != wantDescription {
		t.Errorf("Description: got %q, want %q", got.Description, wantDescription)
	}
	if got.Name != wantName {
		t.Errorf("Name: got %q, want %q", got.Name, wantName)
	}

	// Load the table from a reader.
	r := strings.NewReader("a,0\nb,1\nc,2\n")
	rs := NewReaderSource(r)
	loader := table.LoaderFrom(rs)
	loader.WriteDisposition = WriteTruncate
	job, err := loader.Run(ctx)
	if err != nil {
		t.Fatal(err)
	}
	if err := wait(ctx, job); err != nil {
		t.Fatal(err)
	}
	checkRead(table.Read(ctx))
}

func hasStatusCode(err error, code int) bool {
	if e, ok := err.(*googleapi.Error); ok && e.Code == code {
		return true
	}
	return false
}

// wait polls the job until it is complete or an error is returned.
func wait(ctx context.Context, job *Job) error {
	for {
		status, err := job.Status(ctx)
		if err != nil {
			return fmt.Errorf("getting job status: %v", err)
		}
		if status.Done() {
			if status.Err() != nil {
				return fmt.Errorf("job status: %#v", status.Err())
			}
			return nil
		}
		time.Sleep(1 * time.Second)
	}
}
<commit_msg>bigquery: test inserting data with DML.<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 bigquery

import (
	"fmt"
	"net/http"
	"reflect"
	"sort"
	"strings"
	"testing"
	"time"

	"cloud.google.com/go/internal/pretty"
	"cloud.google.com/go/internal/testutil"
	"golang.org/x/net/context"
	"google.golang.org/api/googleapi"
	"google.golang.org/api/iterator"
	"google.golang.org/api/option"
)

func TestIntegration(t *testing.T) {
	if testing.Short() {
		t.Skip("Integration tests skipped in short mode")
	}

	ctx := context.Background()
	ts := testutil.TokenSource(ctx, Scope)
	if ts == nil {
		t.Skip("Integration tests skipped. See CONTRIBUTING.md for details")
	}

	projID := testutil.ProjID()
	c, err := NewClient(ctx, projID, option.WithTokenSource(ts))
	if err != nil {
		t.Fatal(err)
	}
	ds := c.Dataset("bigquery_integration_test")
	if err := ds.Create(ctx); err != nil && !hasStatusCode(err, http.StatusConflict) { // AlreadyExists is 409
		t.Fatal(err)
	}
	schema := Schema([]*FieldSchema{
		{Name: "name", Type: StringFieldType},
		{Name: "num", Type: IntegerFieldType},
	})
	table := ds.Table("t1")
	// Delete the table in case it already exists. (Ignore errors.)
	table.Delete(ctx)
	// Create the table.
	err = table.Create(ctx, schema, TableExpiration(time.Now().Add(5*time.Minute)))
	if err != nil {
		t.Fatal(err)
	}
	// Check table metadata.
	md, err := table.Metadata(ctx)
	if err != nil {
		t.Fatal(err)
	}
	// TODO(jba): check md more thorougly.
	if got, want := md.ID, fmt.Sprintf("%s:%s.%s", projID, ds.id, table.TableID); got != want {
		t.Errorf("metadata.ID: got %q, want %q", got, want)
	}
	if got, want := md.Type, RegularTable; got != want {
		t.Errorf("metadata.Type: got %v, want %v", got, want)
	}

	// Iterate over tables in the dataset.
	it := ds.Tables(ctx)
	var tables []*Table
	for {
		tbl, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			t.Fatal(err)
		}
		tables = append(tables, tbl)
	}
	if got, want := tables, []*Table{table}; !reflect.DeepEqual(got, want) {
		t.Errorf("Tables: got %v, want %v", pretty.Value(got), pretty.Value(want))
	}

	// Populate the table.
	upl := table.Uploader()
	var rows []*ValuesSaver
	for i, name := range []string{"a", "b", "c"} {
		rows = append(rows, &ValuesSaver{
			Schema:   schema,
			InsertID: name,
			Row:      []Value{name, i},
		})
	}
	if err := upl.Put(ctx, rows); err != nil {
		t.Fatal(err)
	}

	checkRead := func(msg string, it *RowIterator) {
		gotRows, err := readAll(it)
		if err != nil {
			t.Fatal(err)
		}
		if len(gotRows) != len(rows) {
			t.Errorf("%s: got %d rows, want %d", msg, len(gotRows), len(rows))
		}
		sort.Sort(byCol0(gotRows))
		for i, got := range gotRows {
			got := []Value(got)
			want := rows[i].Row
			if !reflect.DeepEqual(got, want) {
				t.Errorf("%s #%d: got %v, want %v", msg, i, got, want)
			}
		}
	}

	// Wait until the data has been uploaded. This can take a few seconds, according
	// to https://cloud.google.com/bigquery/streaming-data-into-bigquery.
	for {
		it := table.Read(ctx)
		var v ValueList
		err := it.Next(&v)
		if err == nil {
			break
		}
		if err != iterator.Done {
			t.Fatal(err)
		}
		time.Sleep(1 * time.Second)
	}

	// Read the table.
	checkRead("upload", table.Read(ctx))

	// Query the table.
	q := c.Query("select name, num from t1")
	q.DefaultProjectID = projID
	q.DefaultDatasetID = ds.id

	rit, err := q.Read(ctx)
	if err != nil {
		t.Fatal(err)
	}
	checkRead("query", rit)

	// Query the long way.
	job1, err := q.Run(ctx)
	if err != nil {
		t.Fatal(err)
	}
	job2, err := c.JobFromID(ctx, job1.ID())
	if err != nil {
		t.Fatal(err)
	}
	// TODO(jba): poll status until job is done
	_, err = job2.Status(ctx)
	if err != nil {
		t.Fatal(err)
	}

	rit, err = job2.Read(ctx)
	if err != nil {
		t.Fatal(err)
	}
	checkRead("job.Read", rit)

	// Test Update.
	tm, err := table.Metadata(ctx)
	if err != nil {
		t.Fatal(err)
	}
	wantDescription := tm.Description + "more"
	wantName := tm.Name + "more"
	got, err := table.Update(ctx, TableMetadataToUpdate{
		Description: wantDescription,
		Name:        wantName,
	})
	if err != nil {
		t.Fatal(err)
	}
	if got.Description != wantDescription {
		t.Errorf("Description: got %q, want %q", got.Description, wantDescription)
	}
	if got.Name != wantName {
		t.Errorf("Name: got %q, want %q", got.Name, wantName)
	}

	// Load the table from a reader.
	r := strings.NewReader("a,0\nb,1\nc,2\n")
	rs := NewReaderSource(r)
	loader := table.LoaderFrom(rs)
	loader.WriteDisposition = WriteTruncate
	job, err := loader.Run(ctx)
	if err != nil {
		t.Fatal(err)
	}
	if err := wait(ctx, job); err != nil {
		t.Fatal(err)
	}
	checkRead("reader load", table.Read(ctx))

	// Use DML to insert.
	// We can't use WriteDisposition to truncate, and CreateIfNeeded doesn't work.
	// So delete and re-create the table.
	if err := table.Delete(ctx); err != nil {
		t.Fatal(err)
	}
	if err := table.Create(ctx, schema, TableExpiration(time.Now().Add(5*time.Minute))); err != nil {
		t.Fatal(err)
	}
	q = c.Query("INSERT bigquery_integration_test.t1 (name, num) VALUES ('a', 0), ('b', 1), ('c', 2)")
	q.UseStandardSQL = true // necessary for DML
	job, err = q.Run(ctx)
	if err != nil {
		t.Fatal(err)
	}
	if err := wait(ctx, job); err != nil {
		t.Fatal(err)
	}
	checkRead("INSERT", table.Read(ctx))
}

func hasStatusCode(err error, code int) bool {
	if e, ok := err.(*googleapi.Error); ok && e.Code == code {
		return true
	}
	return false
}

// wait polls the job until it is complete or an error is returned.
func wait(ctx context.Context, job *Job) error {
	for {
		status, err := job.Status(ctx)
		if err != nil {
			return fmt.Errorf("getting job status: %v", err)
		}
		if status.Done() {
			if status.Err() != nil {
				return fmt.Errorf("job status: %#v", status.Err())
			}
			return nil
		}
		time.Sleep(1 * time.Second)
	}
}

func readAll(it *RowIterator) ([]ValueList, error) {
	var rows []ValueList
	for {
		var vals ValueList
		err := it.Next(&vals)
		if err == iterator.Done {
			return rows, nil
		}
		if err != nil {
			return nil, err
		}
		rows = append(rows, vals)
	}
}

type byCol0 []ValueList

func (b byCol0) Len() int           { return len(b) }
func (b byCol0) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }
func (b byCol0) Less(i, j int) bool { return b[i][0].(string) < b[j][0].(string) }
<|endoftext|>


<commit_before>// +build linux

package specconv

import (
	"os"
	"testing"

	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/opencontainers/runc/libcontainer/configs/validate"
	"github.com/opencontainers/runtime-spec/specs-go"
)

func TestCreateCommandHookTimeout(t *testing.T) {
	timeout := 3600
	hook := specs.Hook{
		Path:    "/some/hook/path",
		Args:    []string{"--some", "thing"},
		Env:     []string{"SOME=value"},
		Timeout: &timeout,
	}
	command := createCommandHook(hook)
	timeoutStr := command.Timeout.String()
	if timeoutStr != "1h0m0s" {
		t.Errorf("Expected the Timeout to be 1h0m0s, got: %s", timeoutStr)
	}
}

func TestCreateHooks(t *testing.T) {
	rspec := &specs.Spec{
		Hooks: &specs.Hooks{
			Prestart: []specs.Hook{
				{
					Path: "/some/hook/path",
				},
				{
					Path: "/some/hook2/path",
					Args: []string{"--some", "thing"},
				},
			},
			Poststart: []specs.Hook{
				{
					Path: "/some/hook/path",
					Args: []string{"--some", "thing"},
					Env:  []string{"SOME=value"},
				},
				{
					Path: "/some/hook2/path",
				},
				{
					Path: "/some/hook3/path",
				},
			},
			Poststop: []specs.Hook{
				{
					Path: "/some/hook/path",
					Args: []string{"--some", "thing"},
					Env:  []string{"SOME=value"},
				},
				{
					Path: "/some/hook2/path",
				},
				{
					Path: "/some/hook3/path",
				},
				{
					Path: "/some/hook4/path",
					Args: []string{"--some", "thing"},
				},
			},
		},
	}
	conf := &configs.Config{}
	createHooks(rspec, conf)

	prestart := conf.Hooks.Prestart

	if len(prestart) != 2 {
		t.Error("Expected 2 Prestart hooks")
	}

	poststart := conf.Hooks.Poststart

	if len(poststart) != 3 {
		t.Error("Expected 3 Poststart hooks")
	}

	poststop := conf.Hooks.Poststop

	if len(poststop) != 4 {
		t.Error("Expected 4 Poststop hooks")
	}

}
func TestSetupSeccomp(t *testing.T) {
	conf := &specs.LinuxSeccomp{
		DefaultAction: "SCMP_ACT_ERRNO",
		Architectures: []specs.Arch{specs.ArchX86_64, specs.ArchARM},
		Syscalls: []specs.LinuxSyscall{
			{
				Names:  []string{"clone"},
				Action: "SCMP_ACT_ALLOW",
				Args: []specs.LinuxSeccompArg{
					{
						Index:    0,
						Value:    2080505856,
						ValueTwo: 0,
						Op:       "SCMP_CMP_MASKED_EQ",
					},
				},
			},
			{
				Names: []string{
					"select",
					"semctl",
					"semget",
					"semop",
					"semtimedop",
					"send",
					"sendfile",
				},
				Action: "SCMP_ACT_ALLOW",
			},
		},
	}
	seccomp, err := SetupSeccomp(conf)

	if err != nil {
		t.Errorf("Couldn't create Seccomp config: %v", err)
	}

	if seccomp.DefaultAction != 2 { // SCMP_ACT_ERRNO
		t.Error("Wrong conversion for DefaultAction")
	}

	if len(seccomp.Architectures) != 2 {
		t.Error("Wrong number of architectures")
	}

	if seccomp.Architectures[0] != "amd64" || seccomp.Architectures[1] != "arm" {
		t.Error("Expected architectures are not found")
	}

	calls := seccomp.Syscalls

	callsLength := len(calls)
	if callsLength != 8 {
		t.Errorf("Expected 8 syscalls, got :%d", callsLength)
	}

	for i, call := range calls {
		if i == 0 {
			expectedCloneSyscallArgs := configs.Arg{
				Index:    0,
				Op:       7, // SCMP_CMP_MASKED_EQ
				Value:    2080505856,
				ValueTwo: 0,
			}
			if expectedCloneSyscallArgs != *call.Args[0] {
				t.Errorf("Wrong arguments conversion for the clone syscall under test")
			}
		}
		if call.Action != 4 {
			t.Error("Wrong conversion for the clone syscall action")
		}

	}

}

func TestLinuxCgroupWithMemoryResource(t *testing.T) {
	cgroupsPath := "/user/cgroups/path/id"

	spec := &specs.Spec{}
	devices := []specs.LinuxDeviceCgroup{
		{
			Allow:  false,
			Access: "rwm",
		},
	}

	limit := int64(100)
	reservation := int64(50)
	swap := int64(20)
	kernel := int64(40)
	kernelTCP := int64(45)
	swappiness := uint64(1)
	swappinessPtr := &swappiness
	disableOOMKiller := true
	resources := &specs.LinuxResources{
		Devices: devices,
		Memory: &specs.LinuxMemory{
			Limit:            &limit,
			Reservation:      &reservation,
			Swap:             &swap,
			Kernel:           &kernel,
			KernelTCP:        &kernelTCP,
			Swappiness:       swappinessPtr,
			DisableOOMKiller: &disableOOMKiller,
		},
	}
	spec.Linux = &specs.Linux{
		CgroupsPath: cgroupsPath,
		Resources:   resources,
	}

	opts := &CreateOpts{
		CgroupName:       "ContainerID",
		UseSystemdCgroup: false,
		Spec:             spec,
	}

	cgroup, err := createCgroupConfig(opts)
	if err != nil {
		t.Errorf("Couldn't create Cgroup config: %v", err)
	}

	if cgroup.Path != cgroupsPath {
		t.Errorf("Wrong cgroupsPath, expected '%s' got '%s'", cgroupsPath, cgroup.Path)
	}
	if cgroup.Resources.Memory != limit {
		t.Errorf("Expected to have %d as memory limit, got %d", limit, cgroup.Resources.Memory)
	}
	if cgroup.Resources.MemoryReservation != reservation {
		t.Errorf("Expected to have %d as memory reservation, got %d", reservation, cgroup.Resources.MemoryReservation)
	}
	if cgroup.Resources.MemorySwap != swap {
		t.Errorf("Expected to have %d as swap, got %d", swap, cgroup.Resources.MemorySwap)
	}
	if cgroup.Resources.KernelMemory != kernel {
		t.Errorf("Expected to have %d as Kernel Memory, got %d", kernel, cgroup.Resources.KernelMemory)
	}
	if cgroup.Resources.KernelMemoryTCP != kernelTCP {
		t.Errorf("Expected to have %d as TCP Kernel Memory, got %d", kernelTCP, cgroup.Resources.KernelMemoryTCP)
	}
	if cgroup.Resources.MemorySwappiness != swappinessPtr {
		t.Errorf("Expected to have %d as memory swappiness, got %d", swappinessPtr, cgroup.Resources.MemorySwappiness)
	}
	if cgroup.Resources.OomKillDisable != disableOOMKiller {
		t.Errorf("The OOMKiller should be enabled")
	}
}

func TestLinuxCgroupSystemd(t *testing.T) {
	cgroupsPath := "parent:scopeprefix:name"

	spec := &specs.Spec{}
	spec.Linux = &specs.Linux{
		CgroupsPath: cgroupsPath,
	}

	opts := &CreateOpts{
		UseSystemdCgroup: true,
		Spec:             spec,
	}

	cgroup, err := createCgroupConfig(opts)

	if err != nil {
		t.Errorf("Couldn't create Cgroup config: %v", err)
	}

	expectedParent := "parent"
	if cgroup.Parent != expectedParent {
		t.Errorf("Expected to have %s as Parent instead of %s", expectedParent, cgroup.Parent)
	}

	expectedScopePrefix := "scopeprefix"
	if cgroup.ScopePrefix != expectedScopePrefix {
		t.Errorf("Expected to have %s as ScopePrefix instead of %s", expectedScopePrefix, cgroup.ScopePrefix)
	}

	expectedName := "name"
	if cgroup.Name != expectedName {
		t.Errorf("Expected to have %s as Name instead of %s", expectedName, cgroup.Name)
	}
}

func TestLinuxCgroupSystemdWithEmptyPath(t *testing.T) {
	cgroupsPath := ""

	spec := &specs.Spec{}
	spec.Linux = &specs.Linux{
		CgroupsPath: cgroupsPath,
	}

	opts := &CreateOpts{
		CgroupName:       "ContainerID",
		UseSystemdCgroup: true,
		Spec:             spec,
	}

	cgroup, err := createCgroupConfig(opts)

	if err != nil {
		t.Errorf("Couldn't create Cgroup config: %v", err)
	}

	expectedParent := "system.slice"
	if cgroup.Parent != expectedParent {
		t.Errorf("Expected to have %s as Parent instead of %s", expectedParent, cgroup.Parent)
	}

	expectedScopePrefix := "runc"
	if cgroup.ScopePrefix != expectedScopePrefix {
		t.Errorf("Expected to have %s as ScopePrefix instead of %s", expectedScopePrefix, cgroup.ScopePrefix)
	}

	if cgroup.Name != opts.CgroupName {
		t.Errorf("Expected to have %s as Name instead of %s", opts.CgroupName, cgroup.Name)
	}
}

func TestLinuxCgroupSystemdWithInvalidPath(t *testing.T) {
	cgroupsPath := "/user/cgroups/path/id"

	spec := &specs.Spec{}
	spec.Linux = &specs.Linux{
		CgroupsPath: cgroupsPath,
	}

	opts := &CreateOpts{
		CgroupName:       "ContainerID",
		UseSystemdCgroup: true,
		Spec:             spec,
	}

	_, err := createCgroupConfig(opts)
	if err == nil {
		t.Error("Expected to produce an error if not using the correct format for cgroup paths belonging to systemd")
	}
}
func TestLinuxCgroupsPathSpecified(t *testing.T) {
	cgroupsPath := "/user/cgroups/path/id"

	spec := &specs.Spec{}
	spec.Linux = &specs.Linux{
		CgroupsPath: cgroupsPath,
	}

	opts := &CreateOpts{
		CgroupName:       "ContainerID",
		UseSystemdCgroup: false,
		Spec:             spec,
	}

	cgroup, err := createCgroupConfig(opts)
	if err != nil {
		t.Errorf("Couldn't create Cgroup config: %v", err)
	}

	if cgroup.Path != cgroupsPath {
		t.Errorf("Wrong cgroupsPath, expected '%s' got '%s'", cgroupsPath, cgroup.Path)
	}
}

func TestLinuxCgroupsPathNotSpecified(t *testing.T) {
	spec := &specs.Spec{}
	opts := &CreateOpts{
		CgroupName:       "ContainerID",
		UseSystemdCgroup: false,
		Spec:             spec,
	}

	cgroup, err := createCgroupConfig(opts)
	if err != nil {
		t.Errorf("Couldn't create Cgroup config: %v", err)
	}

	if cgroup.Path != "" {
		t.Errorf("Wrong cgroupsPath, expected it to be empty string, got '%s'", cgroup.Path)
	}
}

func TestSpecconvExampleValidate(t *testing.T) {
	spec := Example()
	spec.Root.Path = "/"

	opts := &CreateOpts{
		CgroupName:       "ContainerID",
		UseSystemdCgroup: false,
		Spec:             spec,
	}

	config, err := CreateLibcontainerConfig(opts)
	if err != nil {
		t.Errorf("Couldn't create libcontainer config: %v", err)
	}

	validator := validate.New()
	if err := validator.Validate(config); err != nil {
		t.Errorf("Expected specconv to produce valid container config: %v", err)
	}
}

func TestDupNamespaces(t *testing.T) {
	spec := &specs.Spec{
		Linux: &specs.Linux{
			Namespaces: []specs.LinuxNamespace{
				{
					Type: "pid",
				},
				{
					Type: "pid",
					Path: "/proc/1/ns/pid",
				},
			},
		},
	}

	_, err := CreateLibcontainerConfig(&CreateOpts{
		Spec: spec,
	})

	if err == nil {
		t.Errorf("Duplicated namespaces should be forbidden")
	}
}

func TestNonZeroEUIDCompatibleSpecconvValidate(t *testing.T) {
	if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) {
		t.Skip("userns is unsupported")
	}

	spec := Example()
	spec.Root.Path = "/"
	ToRootless(spec)

	opts := &CreateOpts{
		CgroupName:       "ContainerID",
		UseSystemdCgroup: false,
		Spec:             spec,
		RootlessEUID:     true,
		RootlessCgroups:  true,
	}

	config, err := CreateLibcontainerConfig(opts)
	if err != nil {
		t.Errorf("Couldn't create libcontainer config: %v", err)
	}

	validator := validate.New()
	if err := validator.Validate(config); err != nil {
		t.Errorf("Expected specconv to produce valid rootless container config: %v", err)
	}
}
<commit_msg>test: fix TestDupNamespaces<commit_after>// +build linux

package specconv

import (
	"os"
	"strings"
	"testing"

	"github.com/opencontainers/runc/libcontainer/configs"
	"github.com/opencontainers/runc/libcontainer/configs/validate"
	"github.com/opencontainers/runtime-spec/specs-go"
)

func TestCreateCommandHookTimeout(t *testing.T) {
	timeout := 3600
	hook := specs.Hook{
		Path:    "/some/hook/path",
		Args:    []string{"--some", "thing"},
		Env:     []string{"SOME=value"},
		Timeout: &timeout,
	}
	command := createCommandHook(hook)
	timeoutStr := command.Timeout.String()
	if timeoutStr != "1h0m0s" {
		t.Errorf("Expected the Timeout to be 1h0m0s, got: %s", timeoutStr)
	}
}

func TestCreateHooks(t *testing.T) {
	rspec := &specs.Spec{
		Hooks: &specs.Hooks{
			Prestart: []specs.Hook{
				{
					Path: "/some/hook/path",
				},
				{
					Path: "/some/hook2/path",
					Args: []string{"--some", "thing"},
				},
			},
			Poststart: []specs.Hook{
				{
					Path: "/some/hook/path",
					Args: []string{"--some", "thing"},
					Env:  []string{"SOME=value"},
				},
				{
					Path: "/some/hook2/path",
				},
				{
					Path: "/some/hook3/path",
				},
			},
			Poststop: []specs.Hook{
				{
					Path: "/some/hook/path",
					Args: []string{"--some", "thing"},
					Env:  []string{"SOME=value"},
				},
				{
					Path: "/some/hook2/path",
				},
				{
					Path: "/some/hook3/path",
				},
				{
					Path: "/some/hook4/path",
					Args: []string{"--some", "thing"},
				},
			},
		},
	}
	conf := &configs.Config{}
	createHooks(rspec, conf)

	prestart := conf.Hooks.Prestart

	if len(prestart) != 2 {
		t.Error("Expected 2 Prestart hooks")
	}

	poststart := conf.Hooks.Poststart

	if len(poststart) != 3 {
		t.Error("Expected 3 Poststart hooks")
	}

	poststop := conf.Hooks.Poststop

	if len(poststop) != 4 {
		t.Error("Expected 4 Poststop hooks")
	}

}
func TestSetupSeccomp(t *testing.T) {
	conf := &specs.LinuxSeccomp{
		DefaultAction: "SCMP_ACT_ERRNO",
		Architectures: []specs.Arch{specs.ArchX86_64, specs.ArchARM},
		Syscalls: []specs.LinuxSyscall{
			{
				Names:  []string{"clone"},
				Action: "SCMP_ACT_ALLOW",
				Args: []specs.LinuxSeccompArg{
					{
						Index:    0,
						Value:    2080505856,
						ValueTwo: 0,
						Op:       "SCMP_CMP_MASKED_EQ",
					},
				},
			},
			{
				Names: []string{
					"select",
					"semctl",
					"semget",
					"semop",
					"semtimedop",
					"send",
					"sendfile",
				},
				Action: "SCMP_ACT_ALLOW",
			},
		},
	}
	seccomp, err := SetupSeccomp(conf)

	if err != nil {
		t.Errorf("Couldn't create Seccomp config: %v", err)
	}

	if seccomp.DefaultAction != 2 { // SCMP_ACT_ERRNO
		t.Error("Wrong conversion for DefaultAction")
	}

	if len(seccomp.Architectures) != 2 {
		t.Error("Wrong number of architectures")
	}

	if seccomp.Architectures[0] != "amd64" || seccomp.Architectures[1] != "arm" {
		t.Error("Expected architectures are not found")
	}

	calls := seccomp.Syscalls

	callsLength := len(calls)
	if callsLength != 8 {
		t.Errorf("Expected 8 syscalls, got :%d", callsLength)
	}

	for i, call := range calls {
		if i == 0 {
			expectedCloneSyscallArgs := configs.Arg{
				Index:    0,
				Op:       7, // SCMP_CMP_MASKED_EQ
				Value:    2080505856,
				ValueTwo: 0,
			}
			if expectedCloneSyscallArgs != *call.Args[0] {
				t.Errorf("Wrong arguments conversion for the clone syscall under test")
			}
		}
		if call.Action != 4 {
			t.Error("Wrong conversion for the clone syscall action")
		}

	}

}

func TestLinuxCgroupWithMemoryResource(t *testing.T) {
	cgroupsPath := "/user/cgroups/path/id"

	spec := &specs.Spec{}
	devices := []specs.LinuxDeviceCgroup{
		{
			Allow:  false,
			Access: "rwm",
		},
	}

	limit := int64(100)
	reservation := int64(50)
	swap := int64(20)
	kernel := int64(40)
	kernelTCP := int64(45)
	swappiness := uint64(1)
	swappinessPtr := &swappiness
	disableOOMKiller := true
	resources := &specs.LinuxResources{
		Devices: devices,
		Memory: &specs.LinuxMemory{
			Limit:            &limit,
			Reservation:      &reservation,
			Swap:             &swap,
			Kernel:           &kernel,
			KernelTCP:        &kernelTCP,
			Swappiness:       swappinessPtr,
			DisableOOMKiller: &disableOOMKiller,
		},
	}
	spec.Linux = &specs.Linux{
		CgroupsPath: cgroupsPath,
		Resources:   resources,
	}

	opts := &CreateOpts{
		CgroupName:       "ContainerID",
		UseSystemdCgroup: false,
		Spec:             spec,
	}

	cgroup, err := createCgroupConfig(opts)
	if err != nil {
		t.Errorf("Couldn't create Cgroup config: %v", err)
	}

	if cgroup.Path != cgroupsPath {
		t.Errorf("Wrong cgroupsPath, expected '%s' got '%s'", cgroupsPath, cgroup.Path)
	}
	if cgroup.Resources.Memory != limit {
		t.Errorf("Expected to have %d as memory limit, got %d", limit, cgroup.Resources.Memory)
	}
	if cgroup.Resources.MemoryReservation != reservation {
		t.Errorf("Expected to have %d as memory reservation, got %d", reservation, cgroup.Resources.MemoryReservation)
	}
	if cgroup.Resources.MemorySwap != swap {
		t.Errorf("Expected to have %d as swap, got %d", swap, cgroup.Resources.MemorySwap)
	}
	if cgroup.Resources.KernelMemory != kernel {
		t.Errorf("Expected to have %d as Kernel Memory, got %d", kernel, cgroup.Resources.KernelMemory)
	}
	if cgroup.Resources.KernelMemoryTCP != kernelTCP {
		t.Errorf("Expected to have %d as TCP Kernel Memory, got %d", kernelTCP, cgroup.Resources.KernelMemoryTCP)
	}
	if cgroup.Resources.MemorySwappiness != swappinessPtr {
		t.Errorf("Expected to have %d as memory swappiness, got %d", swappinessPtr, cgroup.Resources.MemorySwappiness)
	}
	if cgroup.Resources.OomKillDisable != disableOOMKiller {
		t.Errorf("The OOMKiller should be enabled")
	}
}

func TestLinuxCgroupSystemd(t *testing.T) {
	cgroupsPath := "parent:scopeprefix:name"

	spec := &specs.Spec{}
	spec.Linux = &specs.Linux{
		CgroupsPath: cgroupsPath,
	}

	opts := &CreateOpts{
		UseSystemdCgroup: true,
		Spec:             spec,
	}

	cgroup, err := createCgroupConfig(opts)

	if err != nil {
		t.Errorf("Couldn't create Cgroup config: %v", err)
	}

	expectedParent := "parent"
	if cgroup.Parent != expectedParent {
		t.Errorf("Expected to have %s as Parent instead of %s", expectedParent, cgroup.Parent)
	}

	expectedScopePrefix := "scopeprefix"
	if cgroup.ScopePrefix != expectedScopePrefix {
		t.Errorf("Expected to have %s as ScopePrefix instead of %s", expectedScopePrefix, cgroup.ScopePrefix)
	}

	expectedName := "name"
	if cgroup.Name != expectedName {
		t.Errorf("Expected to have %s as Name instead of %s", expectedName, cgroup.Name)
	}
}

func TestLinuxCgroupSystemdWithEmptyPath(t *testing.T) {
	cgroupsPath := ""

	spec := &specs.Spec{}
	spec.Linux = &specs.Linux{
		CgroupsPath: cgroupsPath,
	}

	opts := &CreateOpts{
		CgroupName:       "ContainerID",
		UseSystemdCgroup: true,
		Spec:             spec,
	}

	cgroup, err := createCgroupConfig(opts)

	if err != nil {
		t.Errorf("Couldn't create Cgroup config: %v", err)
	}

	expectedParent := "system.slice"
	if cgroup.Parent != expectedParent {
		t.Errorf("Expected to have %s as Parent instead of %s", expectedParent, cgroup.Parent)
	}

	expectedScopePrefix := "runc"
	if cgroup.ScopePrefix != expectedScopePrefix {
		t.Errorf("Expected to have %s as ScopePrefix instead of %s", expectedScopePrefix, cgroup.ScopePrefix)
	}

	if cgroup.Name != opts.CgroupName {
		t.Errorf("Expected to have %s as Name instead of %s", opts.CgroupName, cgroup.Name)
	}
}

func TestLinuxCgroupSystemdWithInvalidPath(t *testing.T) {
	cgroupsPath := "/user/cgroups/path/id"

	spec := &specs.Spec{}
	spec.Linux = &specs.Linux{
		CgroupsPath: cgroupsPath,
	}

	opts := &CreateOpts{
		CgroupName:       "ContainerID",
		UseSystemdCgroup: true,
		Spec:             spec,
	}

	_, err := createCgroupConfig(opts)
	if err == nil {
		t.Error("Expected to produce an error if not using the correct format for cgroup paths belonging to systemd")
	}
}
func TestLinuxCgroupsPathSpecified(t *testing.T) {
	cgroupsPath := "/user/cgroups/path/id"

	spec := &specs.Spec{}
	spec.Linux = &specs.Linux{
		CgroupsPath: cgroupsPath,
	}

	opts := &CreateOpts{
		CgroupName:       "ContainerID",
		UseSystemdCgroup: false,
		Spec:             spec,
	}

	cgroup, err := createCgroupConfig(opts)
	if err != nil {
		t.Errorf("Couldn't create Cgroup config: %v", err)
	}

	if cgroup.Path != cgroupsPath {
		t.Errorf("Wrong cgroupsPath, expected '%s' got '%s'", cgroupsPath, cgroup.Path)
	}
}

func TestLinuxCgroupsPathNotSpecified(t *testing.T) {
	spec := &specs.Spec{}
	opts := &CreateOpts{
		CgroupName:       "ContainerID",
		UseSystemdCgroup: false,
		Spec:             spec,
	}

	cgroup, err := createCgroupConfig(opts)
	if err != nil {
		t.Errorf("Couldn't create Cgroup config: %v", err)
	}

	if cgroup.Path != "" {
		t.Errorf("Wrong cgroupsPath, expected it to be empty string, got '%s'", cgroup.Path)
	}
}

func TestSpecconvExampleValidate(t *testing.T) {
	spec := Example()
	spec.Root.Path = "/"

	opts := &CreateOpts{
		CgroupName:       "ContainerID",
		UseSystemdCgroup: false,
		Spec:             spec,
	}

	config, err := CreateLibcontainerConfig(opts)
	if err != nil {
		t.Errorf("Couldn't create libcontainer config: %v", err)
	}

	validator := validate.New()
	if err := validator.Validate(config); err != nil {
		t.Errorf("Expected specconv to produce valid container config: %v", err)
	}
}

func TestDupNamespaces(t *testing.T) {
	spec := &specs.Spec{
		Root: &specs.Root{
			Path: "rootfs",
		},
		Linux: &specs.Linux{
			Namespaces: []specs.LinuxNamespace{
				{
					Type: "pid",
				},
				{
					Type: "pid",
					Path: "/proc/1/ns/pid",
				},
			},
		},
	}

	_, err := CreateLibcontainerConfig(&CreateOpts{
		Spec: spec,
	})

	if !strings.Contains(err.Error(), "malformed spec file: duplicated ns") {
		t.Errorf("Duplicated namespaces should be forbidden")
	}
}

func TestNonZeroEUIDCompatibleSpecconvValidate(t *testing.T) {
	if _, err := os.Stat("/proc/self/ns/user"); os.IsNotExist(err) {
		t.Skip("userns is unsupported")
	}

	spec := Example()
	spec.Root.Path = "/"
	ToRootless(spec)

	opts := &CreateOpts{
		CgroupName:       "ContainerID",
		UseSystemdCgroup: false,
		Spec:             spec,
		RootlessEUID:     true,
		RootlessCgroups:  true,
	}

	config, err := CreateLibcontainerConfig(opts)
	if err != nil {
		t.Errorf("Couldn't create libcontainer config: %v", err)
	}

	validator := validate.New()
	if err := validator.Validate(config); err != nil {
		t.Errorf("Expected specconv to produce valid rootless container config: %v", err)
	}
}
<|endoftext|>


<commit_before>package shufn_test

import (
	"fmt"
	"math/rand"
	"sort"

	"github.com/icio/shufn"
)

func ExampleSimple() {
	// it produces values in the range 0-100 inclusive. The start parameter is
	// passed through to New verbatim. When New receives start=0 it replaces it
	// with a random value.
	rand.Seed(0)
	it := shufn.New(shufn.Calc(1, 3, 0))
	for {
		i, more := it.Next()
		if !more {
			break
		}

		fmt.Println(i)
	}
	// Output: 1
	// 3
	// 2
}

func ExampleParallel() {
	work := make(chan int)
	done := make(chan int)

	// Distribute the random values via a channel.
	go func(it shufn.Iter) {
		for {
			i, more := it.Next()
			if !more {
				break
			}
			work <- int(i)
		}
		close(work)
	}(shufn.New(shufn.Calc(0, 10, 0)))

	// Create two workers to square each integer on the work queue and write to done.
	W, workers := 2, make(chan bool)
	for w := 0; w < W; w++ {
		go func(work chan int, done chan int) {
			for n := range work {
				done <- n * n
			}
			workers <- true
		}(work, done)
	}

	// Close the done channel after the workers have completed.
	go func() {
		for w := 0; w < W; w++ {
			<-workers
		}
		close(done)
	}()

	// Collect and sort the results.
	squares := make(chan []int)
	go func() {
		sqs := make([]int, 0, 10)
		for sq := range done {
			sqs = append(sqs, sq)
		}
		sort.Ints(sqs)
		squares <- sqs
	}()

	fmt.Println(<-squares)
	// Output: [0 1 4 9 16 25 36 49 64 81 100]
}
<commit_msg>Fix example names<commit_after>package shufn_test

import (
	"fmt"
	"math/rand"
	"sort"

	"github.com/icio/shufn"
)

func ExampleNew() {
	// it produces values in the range 0-100 inclusive. The start parameter is
	// passed through to New verbatim. When New receives start=0 it replaces it
	// with a random value.
	rand.Seed(0)
	it := shufn.New(shufn.Calc(1, 3, 0))
	for {
		i, more := it.Next()
		if !more {
			break
		}

		fmt.Println(i)
	}
	// Output: 1
	// 3
	// 2
}

func ExampleNew_Parallel() {
	work := make(chan int)
	done := make(chan int)

	// Distribute the random values via a channel.
	go func(it shufn.Iter) {
		for {
			i, more := it.Next()
			if !more {
				break
			}
			work <- int(i)
		}
		close(work)
	}(shufn.New(shufn.Calc(0, 10, 0)))

	// Create two workers to square each integer on the work queue and write to done.
	W, workers := 2, make(chan bool)
	for w := 0; w < W; w++ {
		go func(work chan int, done chan int) {
			for n := range work {
				done <- n * n
			}
			workers <- true
		}(work, done)
	}

	// Close the done channel after the workers have completed.
	go func() {
		for w := 0; w < W; w++ {
			<-workers
		}
		close(done)
	}()

	// Collect and sort the results.
	squares := make(chan []int)
	go func() {
		sqs := make([]int, 0, 10)
		for sq := range done {
			sqs = append(sqs, sq)
		}
		sort.Ints(sqs)
		squares <- sqs
	}()

	fmt.Println(<-squares)
	// Output: [0 1 4 9 16 25 36 49 64 81 100]
}
<|endoftext|>


<commit_before>package orient

import (
	"bytes"
	"fmt"
	"time"

	//	"database/sql/driver"
	"reflect"
	"strings"
)

var (
	_ OIdentifiable        = (*Document)(nil)
	_ DocumentSerializable = (*Document)(nil)
	_ MapSerializable      = (*Document)(nil)
	_ ORecord              = (*Document)(nil)
)

// DocEntry is a generic data holder that goes in Documents.
type DocEntry struct {
	Name  string
	Type  OType
	Value interface{}
}

func (fld *DocEntry) String() string {
	if id, ok := fld.Value.(OIdentifiable); ok {
		return fmt.Sprintf("{%s(%s): %v}", fld.Name, fld.Type, id.GetIdentity())
	}
	return fmt.Sprintf("{%s(%s): %v}", fld.Name, fld.Type, fld.Value)
}

type Document struct {
	BytesRecord
	serialized  bool
	fieldsOrder []string // field names in the order they were added to the Document
	fields      map[string]*DocEntry
	classname   string // TODO: probably needs to change *OClass (once that is built)
	dirty       bool
	ser         RecordSerializer
}

func (doc *Document) ClassName() string { return doc.classname }

// NewDocument should be called to create new Document objects,
// since some internal data structures need to be initialized
// before the Document is ready to use.
func NewDocument(className string) *Document {
	doc := NewEmptyDocument()
	doc.classname = className
	return doc
}

// NewEmptyDocument creates new empty document.
func NewEmptyDocument() *Document {
	return &Document{
		BytesRecord: BytesRecord{
			RID:  NewEmptyRID(),
			Vers: -1,
		},
		fields: make(map[string]*DocEntry),
		ser:    GetDefaultRecordSerializer(),
	}
}

// NewDocumentFromRID creates new empty document with given RID.
func NewDocumentFromRID(rid RID) *Document {
	return &Document{
		BytesRecord: BytesRecord{
			RID:  rid,
			Vers: -1,
		},
		fields: make(map[string]*DocEntry),
		ser:    GetDefaultRecordSerializer(),
	}
}

func (doc *Document) ensureDecoded() error {
	if doc == nil {
		return fmt.Errorf("nil document")
	}
	if !doc.serialized {
		return nil
	}
	o, err := doc.ser.FromStream(doc.BytesRecord.Data)
	if err != nil {
		return err
	}
	ndoc, ok := o.(*Document)
	if !ok {
		return fmt.Errorf("expected document, got %T", o)
	}
	doc.classname = ndoc.classname
	doc.fields = ndoc.fields
	doc.fieldsOrder = ndoc.fieldsOrder
	doc.serialized = false
	return nil
}

func (doc *Document) Content() ([]byte, error) {
	// TODO: can track field changes and invalidate content if necessary - no need to serialize each time
	if doc.serialized {
		return doc.BytesRecord.Content()
	}
	buf := bytes.NewBuffer(nil)
	if err := doc.ser.ToStream(buf, doc); err != nil {
		return nil, err
	}
	doc.BytesRecord.Data = buf.Bytes()
	return doc.BytesRecord.Content()
}

func (doc *Document) GetIdentity() RID {
	if doc == nil {
		return NewEmptyRID()
	}
	return doc.BytesRecord.GetIdentity()
}

func (doc *Document) GetRecord() interface{} {
	if doc == nil {
		return nil
	}
	return doc
}

// FieldNames returns the names of all the fields currently in this Document
// in "entry order". These fields may not have already been committed to the database.
func (doc *Document) FieldNames() []string {
	doc.ensureDecoded()
	names := make([]string, len(doc.fieldsOrder))
	copy(names, doc.fieldsOrder)
	return names
}

func (doc *Document) Fields() map[string]*DocEntry {
	doc.ensureDecoded()
	return doc.fields // TODO: copy map?
}

// FieldsArray return the OField objects in the Document in "entry order".
// There is some overhead to getting them in entry order, so if you
// don't care about that order, just access the Fields field of the
// Document struct directly.
func (doc *Document) FieldsArray() []*DocEntry {
	doc.ensureDecoded()
	fields := make([]*DocEntry, len(doc.fieldsOrder))
	for i, name := range doc.fieldsOrder {
		fields[i] = doc.fields[name]
	}
	return fields
}

// GetFieldByName looks up the OField in this document with the specified field.
// If no field is found with that name, nil is returned.
func (doc *Document) GetField(fname string) *DocEntry {
	doc.ensureDecoded()
	return doc.fields[fname]
}

// AddField adds a fully created field directly rather than by some of its
// attributes, as the other "Field" methods do.
// The same *Document is returned to allow call chaining.
func (doc *Document) AddField(name string, field *DocEntry) *Document {
	doc.ensureDecoded()
	doc.fields[name] = field
	doc.fieldsOrder = append(doc.fieldsOrder, name)
	doc.dirty = true
	return doc
}

func (doc *Document) SetDirty(b bool) {
	doc.dirty = b
}

// SetField is used to add a new field to a document. This will usually be done just
// before calling Save and sending it to the database.  The field type will be inferred
// via type switch analysis on `val`.  Use FieldWithType to specify the type directly.
// The same *Document is returned to allow call chaining.
func (doc *Document) SetField(name string, val interface{}) *Document {
	doc.ensureDecoded()
	return doc.SetFieldWithType(name, val, OTypeForValue(val))
}

// FieldWithType is used to add a new field to a document. This will usually be done just
// before calling Save and sending it to the database. The `fieldType` must correspond
// one of the OrientDB type in the schema pkg constants.  It will follow the same list
// as: https://github.com/orientechnologies/orientdb/wiki/Types
// The same *Document is returned to allow call chaining.
func (doc *Document) SetFieldWithType(name string, val interface{}, fieldType OType) *Document {
	doc.ensureDecoded()
	fld := &DocEntry{
		Name:  name,
		Value: val,
		Type:  fieldType,
	}

	if fieldType == DATE {
		fld.Value = adjustDateToMidnight(val)
	} else if fieldType == DATETIME {
		fld.Value = roundDateTimeToMillis(val)
	}

	return doc.AddField(name, fld)
}

func (doc *Document) RawContainsField(name string) bool {
	doc.ensureDecoded()
	return doc != nil && doc.fields[name] != nil
}

func (doc *Document) RawSetField(name string, val interface{}, fieldType OType) {
	doc.SetFieldWithType(name, val, fieldType) // TODO: implement in a right way
}

// roundDateTimeToMillis zeros out the micro and nanoseconds of a
// time.Time object in order to match the precision with which
// the OrientDB stores DATETIME values
func roundDateTimeToMillis(val interface{}) interface{} {
	tm, ok := val.(time.Time)
	if !ok {
		// if the type is wrong, we will flag it as an error when the user tries
		// to save it, rather than here while buidling the document
		return val
	}

	return tm.Round(time.Millisecond)
}

// adjustDateToMidnight zeros out the hour, minute, second, etc.
// to set the time of a DATE to midnight.  This matches the
// precision with which the OrientDB stores DATE values.
func adjustDateToMidnight(val interface{}) interface{} {
	tm, ok := val.(time.Time)
	if !ok {
		// if the type is wrong, we will flag it as an error when the user tries
		// to save it, rather than here while buidling the document
		return val
	}
	tmMidnight := time.Date(tm.Year(), tm.Month(), tm.Day(), 0, 0, 0, 0, tm.Location())
	return interface{}(tmMidnight)
}

func (doc *Document) String() string {
	class := doc.classname
	if class == "" {
		class = "<nil>"
	}
	if doc.serialized {
		return fmt.Sprintf("Document{Class: %s, RID: %s, Vers: %d, Fields: [serialized]}",
			class, doc.RID, doc.Vers)
	}
	buf := new(bytes.Buffer)
	_, err := buf.WriteString(fmt.Sprintf("Document{Class: %s, RID: %s, Vers: %d, Fields: [\n",
		class, doc.RID, doc.Vers))
	if err != nil {
		panic(err)
	}

	for _, fld := range doc.fields {
		_, err = buf.WriteString(fmt.Sprintf("  %s,\n", fld.String()))
		if err != nil {
			panic(err)
		}
	}

	buf.WriteString("]}\n")
	return buf.String()
}

func (doc *Document) ToMap() (map[string]interface{}, error) {
	if doc == nil {
		return nil, nil
	}
	if err := doc.ensureDecoded(); err != nil {
		return nil, err
	}
	out := make(map[string]interface{}, len(doc.fields))
	for name, fld := range doc.fields {
		out[name] = fld.Value
	}
	if doc.classname != "" {
		out["@class"] = doc.classname
	}
	if doc.RID.IsPersistent() { // TODO: is this correct?
		out["@rid"] = doc.RID
	}
	return out, nil
}

func (doc *Document) FillClassNameIfNeeded(name string) {
	if doc.classname == "" {
		doc.SetClassNameIfExists(name)
	}
}

func (doc *Document) SetClassNameIfExists(name string) {
	// TODO: implement class lookup
	//	_immutableClazz = null;
	//	_immutableSchemaVersion = -1;

	doc.classname = name
	if name == "" {
		return
	}

	//    final ODatabaseDocument db = getDatabaseIfDefined();
	//    if (db != null) {
	//      final OClass _clazz = ((OMetadataInternal) db.getMetadata()).getImmutableSchemaSnapshot().getClass(iClassName);
	//      if (_clazz != null) {
	//        _className = _clazz.getName();
	//        convertFieldsToClass(_clazz);
	//      }
	//    }
}

// SetSerializer sets RecordSerializer for encoding/decoding a Document
func (doc *Document) SetSerializer(ser RecordSerializer) {
	doc.ser = ser
}
func (doc *Document) Fill(rid RID, version int, content []byte) error {
	doc.serialized = doc.serialized || doc.BytesRecord.Data == nil || bytes.Compare(content, doc.BytesRecord.Data) != 0
	return doc.BytesRecord.Fill(rid, version, content)
}
func (doc *Document) RecordType() RecordType { return RecordTypeDocument }

// ToDocument implement DocumentSerializable interface. In this case, Document just returns itself.
func (doc *Document) ToDocument() (*Document, error) {
	return doc, nil
}

// ToStruct fills provided struct with content of a Document. Argument must be a pointer to structure.
func (doc *Document) ToStruct(o interface{}) error {
	mp, err := doc.ToMap()
	if err != nil {
		return err
	}
	return mapToStruct(mp, o)
}

func (doc *Document) setFieldsFrom(rv reflect.Value) error {
	switch rv.Kind() {
	case reflect.Struct:
		rt := rv.Type()
		for i := 0; i < rt.NumField(); i++ {
			fld := rt.Field(i)
			if !isExported(fld.Name) {
				continue
			}
			name := fld.Name
			tags := strings.Split(fld.Tag.Get(TagName), ",")
			if tags[0] == "-" {
				continue
			}
			if tags[0] != "" {
				name = tags[0]
			}
			squash := (len(tags) > 1 && tags[1] == "squash") // TODO: change default behavior to squash if field is anonymous
			if squash {
				if err := doc.setFieldsFrom(rv.Field(i)); err != nil {
					return fmt.Errorf("field '%s': %s", name, err)
				}
			} else {
				doc.SetField(name, rv.Field(i).Interface())
			}
		}
		return nil
	case reflect.Map:
		for _, key := range rv.MapKeys() {
			doc.SetField(fmt.Sprint(key.Interface()), rv.MapIndex(key).Interface())
		}
		return nil
	default:
		return fmt.Errorf("only maps and structs are supported, got: %T", rv.Interface())
	}
}

// From sets Document fields to values provided in argument (which can be a map or a struct).
//
// From uses TagName field tag to determine field name and conversion parameters.
// For now it supports only one special tag parameter: ",squash" which can be used to inline fields into parent struct.
func (doc *Document) From(o interface{}) error {
	// TODO: clear fields and serialized data
	if o == nil {
		return nil
	}
	rv := reflect.ValueOf(o)
	if rv.Kind() == reflect.Ptr || rv.Kind() == reflect.Interface {
		rv = rv.Elem()
	}
	return doc.setFieldsFrom(rv)
}

/*
// Implements database/sql.Scanner interface
func (doc *Document) Scan(src interface{}) error {
	switch v := src.(type) {
	case *Document:
		*doc = *v
	default:
		return fmt.Errorf("Document: cannot convert from %T to %T", src, doc)
	}
	return nil
}

// Implements database/sql/driver.Valuer interface
// TODO: haven't detected when this is called yet (probably when serializing Document for insertion into DB??)
func (doc *Document) Value() (driver.Value, error) {
	if glog.V(10) {
		glog.Infoln("** Document.Value")
	}
	return []byte(`{"b": 2}`), nil // FIXME: bogus
}

// Implements database/sql/driver.ValueConverter interface
// TODO: haven't detected when this is called yet
func (doc *Document) ConvertValue(v interface{}) (driver.Value, error) {
	if glog.V(10) {
		glog.Infof("** Document.ConvertValue: %T: %v", v, v)
	}
	return []byte(`{"a": 1}`), nil // FIXME: bogus
}*/
<commit_msg>Fix NPE for document with no serializer<commit_after>package orient

import (
	"bytes"
	"fmt"
	"time"

	//	"database/sql/driver"
	"reflect"
	"strings"
)

var (
	_ OIdentifiable        = (*Document)(nil)
	_ DocumentSerializable = (*Document)(nil)
	_ MapSerializable      = (*Document)(nil)
	_ ORecord              = (*Document)(nil)
)

// DocEntry is a generic data holder that goes in Documents.
type DocEntry struct {
	Name  string
	Type  OType
	Value interface{}
}

func (fld *DocEntry) String() string {
	if id, ok := fld.Value.(OIdentifiable); ok {
		return fmt.Sprintf("{%s(%s): %v}", fld.Name, fld.Type, id.GetIdentity())
	}
	return fmt.Sprintf("{%s(%s): %v}", fld.Name, fld.Type, fld.Value)
}

type Document struct {
	BytesRecord
	serialized  bool
	fieldsOrder []string // field names in the order they were added to the Document
	fields      map[string]*DocEntry
	classname   string // TODO: probably needs to change *OClass (once that is built)
	dirty       bool
	ser         RecordSerializer
}

func (doc *Document) ClassName() string { return doc.classname }

// NewDocument should be called to create new Document objects,
// since some internal data structures need to be initialized
// before the Document is ready to use.
func NewDocument(className string) *Document {
	doc := NewEmptyDocument()
	doc.classname = className
	return doc
}

// NewEmptyDocument creates new empty document.
func NewEmptyDocument() *Document {
	return &Document{
		BytesRecord: BytesRecord{
			RID:  NewEmptyRID(),
			Vers: -1,
		},
		fields: make(map[string]*DocEntry),
		ser:    GetDefaultRecordSerializer(),
	}
}

// NewDocumentFromRID creates new empty document with given RID.
func NewDocumentFromRID(rid RID) *Document {
	return &Document{
		BytesRecord: BytesRecord{
			RID:  rid,
			Vers: -1,
		},
		fields: make(map[string]*DocEntry),
		ser:    GetDefaultRecordSerializer(),
	}
}

func (doc *Document) ensureDecoded() error {
	if doc == nil {
		return fmt.Errorf("nil document")
	}
	if !doc.serialized {
		return nil
	}
	o, err := doc.ser.FromStream(doc.BytesRecord.Data)
	if err != nil {
		return err
	}
	ndoc, ok := o.(*Document)
	if !ok {
		return fmt.Errorf("expected document, got %T", o)
	}
	doc.classname = ndoc.classname
	doc.fields = ndoc.fields
	doc.fieldsOrder = ndoc.fieldsOrder
	doc.serialized = false
	return nil
}

func (doc *Document) Content() ([]byte, error) {
	// TODO: can track field changes and invalidate content if necessary - no need to serialize each time
	if doc.serialized {
		return doc.BytesRecord.Content()
	} else if doc.ser == nil {
		return nil, fmt.Errorf("document is not serialized and no serializer is set")
	}
	buf := bytes.NewBuffer(nil)
	if err := doc.ser.ToStream(buf, doc); err != nil {
		return nil, err
	}
	doc.BytesRecord.Data = buf.Bytes()
	return doc.BytesRecord.Content()
}

func (doc *Document) GetIdentity() RID {
	if doc == nil {
		return NewEmptyRID()
	}
	return doc.BytesRecord.GetIdentity()
}

func (doc *Document) GetRecord() interface{} {
	if doc == nil {
		return nil
	}
	return doc
}

// FieldNames returns the names of all the fields currently in this Document
// in "entry order". These fields may not have already been committed to the database.
func (doc *Document) FieldNames() []string {
	doc.ensureDecoded()
	names := make([]string, len(doc.fieldsOrder))
	copy(names, doc.fieldsOrder)
	return names
}

func (doc *Document) Fields() map[string]*DocEntry {
	doc.ensureDecoded()
	return doc.fields // TODO: copy map?
}

// FieldsArray return the OField objects in the Document in "entry order".
// There is some overhead to getting them in entry order, so if you
// don't care about that order, just access the Fields field of the
// Document struct directly.
func (doc *Document) FieldsArray() []*DocEntry {
	doc.ensureDecoded()
	fields := make([]*DocEntry, len(doc.fieldsOrder))
	for i, name := range doc.fieldsOrder {
		fields[i] = doc.fields[name]
	}
	return fields
}

// GetFieldByName looks up the OField in this document with the specified field.
// If no field is found with that name, nil is returned.
func (doc *Document) GetField(fname string) *DocEntry {
	doc.ensureDecoded()
	return doc.fields[fname]
}

// AddField adds a fully created field directly rather than by some of its
// attributes, as the other "Field" methods do.
// The same *Document is returned to allow call chaining.
func (doc *Document) AddField(name string, field *DocEntry) *Document {
	doc.ensureDecoded()
	doc.fields[name] = field
	doc.fieldsOrder = append(doc.fieldsOrder, name)
	doc.dirty = true
	return doc
}

func (doc *Document) SetDirty(b bool) {
	doc.dirty = b
}

// SetField is used to add a new field to a document. This will usually be done just
// before calling Save and sending it to the database.  The field type will be inferred
// via type switch analysis on `val`.  Use FieldWithType to specify the type directly.
// The same *Document is returned to allow call chaining.
func (doc *Document) SetField(name string, val interface{}) *Document {
	doc.ensureDecoded()
	return doc.SetFieldWithType(name, val, OTypeForValue(val))
}

// FieldWithType is used to add a new field to a document. This will usually be done just
// before calling Save and sending it to the database. The `fieldType` must correspond
// one of the OrientDB type in the schema pkg constants.  It will follow the same list
// as: https://github.com/orientechnologies/orientdb/wiki/Types
// The same *Document is returned to allow call chaining.
func (doc *Document) SetFieldWithType(name string, val interface{}, fieldType OType) *Document {
	doc.ensureDecoded()
	fld := &DocEntry{
		Name:  name,
		Value: val,
		Type:  fieldType,
	}

	if fieldType == DATE {
		fld.Value = adjustDateToMidnight(val)
	} else if fieldType == DATETIME {
		fld.Value = roundDateTimeToMillis(val)
	}

	return doc.AddField(name, fld)
}

func (doc *Document) RawContainsField(name string) bool {
	doc.ensureDecoded()
	return doc != nil && doc.fields[name] != nil
}

func (doc *Document) RawSetField(name string, val interface{}, fieldType OType) {
	doc.SetFieldWithType(name, val, fieldType) // TODO: implement in a right way
}

// roundDateTimeToMillis zeros out the micro and nanoseconds of a
// time.Time object in order to match the precision with which
// the OrientDB stores DATETIME values
func roundDateTimeToMillis(val interface{}) interface{} {
	tm, ok := val.(time.Time)
	if !ok {
		// if the type is wrong, we will flag it as an error when the user tries
		// to save it, rather than here while buidling the document
		return val
	}

	return tm.Round(time.Millisecond)
}

// adjustDateToMidnight zeros out the hour, minute, second, etc.
// to set the time of a DATE to midnight.  This matches the
// precision with which the OrientDB stores DATE values.
func adjustDateToMidnight(val interface{}) interface{} {
	tm, ok := val.(time.Time)
	if !ok {
		// if the type is wrong, we will flag it as an error when the user tries
		// to save it, rather than here while buidling the document
		return val
	}
	tmMidnight := time.Date(tm.Year(), tm.Month(), tm.Day(), 0, 0, 0, 0, tm.Location())
	return interface{}(tmMidnight)
}

func (doc *Document) String() string {
	class := doc.classname
	if class == "" {
		class = "<nil>"
	}
	if doc.serialized {
		return fmt.Sprintf("Document{Class: %s, RID: %s, Vers: %d, Fields: [serialized]}",
			class, doc.RID, doc.Vers)
	}
	buf := new(bytes.Buffer)
	_, err := buf.WriteString(fmt.Sprintf("Document{Class: %s, RID: %s, Vers: %d, Fields: [\n",
		class, doc.RID, doc.Vers))
	if err != nil {
		panic(err)
	}

	for _, fld := range doc.fields {
		_, err = buf.WriteString(fmt.Sprintf("  %s,\n", fld.String()))
		if err != nil {
			panic(err)
		}
	}

	buf.WriteString("]}\n")
	return buf.String()
}

func (doc *Document) ToMap() (map[string]interface{}, error) {
	if doc == nil {
		return nil, nil
	}
	if err := doc.ensureDecoded(); err != nil {
		return nil, err
	}
	out := make(map[string]interface{}, len(doc.fields))
	for name, fld := range doc.fields {
		out[name] = fld.Value
	}
	if doc.classname != "" {
		out["@class"] = doc.classname
	}
	if doc.RID.IsPersistent() { // TODO: is this correct?
		out["@rid"] = doc.RID
	}
	return out, nil
}

func (doc *Document) FillClassNameIfNeeded(name string) {
	if doc.classname == "" {
		doc.SetClassNameIfExists(name)
	}
}

func (doc *Document) SetClassNameIfExists(name string) {
	// TODO: implement class lookup
	//	_immutableClazz = null;
	//	_immutableSchemaVersion = -1;

	doc.classname = name
	if name == "" {
		return
	}

	//    final ODatabaseDocument db = getDatabaseIfDefined();
	//    if (db != null) {
	//      final OClass _clazz = ((OMetadataInternal) db.getMetadata()).getImmutableSchemaSnapshot().getClass(iClassName);
	//      if (_clazz != null) {
	//        _className = _clazz.getName();
	//        convertFieldsToClass(_clazz);
	//      }
	//    }
}

// SetSerializer sets RecordSerializer for encoding/decoding a Document
func (doc *Document) SetSerializer(ser RecordSerializer) {
	doc.ser = ser
}
func (doc *Document) Fill(rid RID, version int, content []byte) error {
	doc.serialized = doc.serialized || doc.BytesRecord.Data == nil || bytes.Compare(content, doc.BytesRecord.Data) != 0
	return doc.BytesRecord.Fill(rid, version, content)
}
func (doc *Document) RecordType() RecordType { return RecordTypeDocument }

// ToDocument implement DocumentSerializable interface. In this case, Document just returns itself.
func (doc *Document) ToDocument() (*Document, error) {
	return doc, nil
}

// ToStruct fills provided struct with content of a Document. Argument must be a pointer to structure.
func (doc *Document) ToStruct(o interface{}) error {
	mp, err := doc.ToMap()
	if err != nil {
		return err
	}
	return mapToStruct(mp, o)
}

func (doc *Document) setFieldsFrom(rv reflect.Value) error {
	switch rv.Kind() {
	case reflect.Struct:
		rt := rv.Type()
		for i := 0; i < rt.NumField(); i++ {
			fld := rt.Field(i)
			if !isExported(fld.Name) {
				continue
			}
			name := fld.Name
			tags := strings.Split(fld.Tag.Get(TagName), ",")
			if tags[0] == "-" {
				continue
			}
			if tags[0] != "" {
				name = tags[0]
			}
			squash := (len(tags) > 1 && tags[1] == "squash") // TODO: change default behavior to squash if field is anonymous
			if squash {
				if err := doc.setFieldsFrom(rv.Field(i)); err != nil {
					return fmt.Errorf("field '%s': %s", name, err)
				}
			} else {
				doc.SetField(name, rv.Field(i).Interface())
			}
		}
		return nil
	case reflect.Map:
		for _, key := range rv.MapKeys() {
			doc.SetField(fmt.Sprint(key.Interface()), rv.MapIndex(key).Interface())
		}
		return nil
	default:
		return fmt.Errorf("only maps and structs are supported, got: %T", rv.Interface())
	}
}

// From sets Document fields to values provided in argument (which can be a map or a struct).
//
// From uses TagName field tag to determine field name and conversion parameters.
// For now it supports only one special tag parameter: ",squash" which can be used to inline fields into parent struct.
func (doc *Document) From(o interface{}) error {
	// TODO: clear fields and serialized data
	if o == nil {
		return nil
	}
	rv := reflect.ValueOf(o)
	if rv.Kind() == reflect.Ptr || rv.Kind() == reflect.Interface {
		rv = rv.Elem()
	}
	return doc.setFieldsFrom(rv)
}

/*
// Implements database/sql.Scanner interface
func (doc *Document) Scan(src interface{}) error {
	switch v := src.(type) {
	case *Document:
		*doc = *v
	default:
		return fmt.Errorf("Document: cannot convert from %T to %T", src, doc)
	}
	return nil
}

// Implements database/sql/driver.Valuer interface
// TODO: haven't detected when this is called yet (probably when serializing Document for insertion into DB??)
func (doc *Document) Value() (driver.Value, error) {
	if glog.V(10) {
		glog.Infoln("** Document.Value")
	}
	return []byte(`{"b": 2}`), nil // FIXME: bogus
}

// Implements database/sql/driver.ValueConverter interface
// TODO: haven't detected when this is called yet
func (doc *Document) ConvertValue(v interface{}) (driver.Value, error) {
	if glog.V(10) {
		glog.Infof("** Document.ConvertValue: %T: %v", v, v)
	}
	return []byte(`{"a": 1}`), nil // FIXME: bogus
}*/
<|endoftext|>


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

// Rule Set API support - Fetch, Create, Update, Delete, and Search
// See: https://login.circonus.com/resources/api/calls/rule_set

package api

import (
	"encoding/json"
	"fmt"
	"net/url"
	"regexp"

	"github.com/circonus-labs/circonus-gometrics/api/config"
)

// RuleSetRule defines a ruleset rule
type RuleSetRule struct {
	Criteria          string  `json:"criteria"`                     // string
	Severity          uint    `json:"severity"`                     // uint
	Value             string  `json:"value"`                        // string
	Wait              uint    `json:"wait"`                         // uint
	WindowingDuration uint    `json:"windowing_duration,omitempty"` // uint
	WindowingFunction *string `json:"windowing_function,omitempty"` // string or null
}

// RuleSet defines a ruleset. See https://login.circonus.com/resources/api/calls/rule_set for more information.
type RuleSet struct {
	CheckCID      string             `json:"check"`            // string
	CID           string             `json:"_cid,omitempty"`   // string
	ContactGroups map[uint8][]string `json:"contact_groups"`   // [] len 5
	Derive        *string            `json:"derive,omitempty"` // string or null
	Link          *string            `json:"link"`             // string or null
	MetricName    string             `json:"metric_name"`      // string
	MetricTags    []string           `json:"metric_tags"`      // [] len >= 0
	MetricType    string             `json:"metric_type"`      // string
	Notes         *string            `json:"notes"`            // string or null
	Parent        *string            `json:"parent,omitempty"` // string or null
	Rules         []RuleSetRule      `json:"rules"`            // [] len >= 1
	Tags          []string           `json:"tags"`             // [] len >= 0
}

// NewRuleSet returns a new RuleSet (with defaults if applicable)
func NewRuleSet() *RuleSet {
	return &RuleSet{}
}

// FetchRuleSet retrieves rule set with passed cid.
func (a *API) FetchRuleSet(cid CIDType) (*RuleSet, error) {
	if cid == nil || *cid == "" {
		return nil, fmt.Errorf("Invalid rule set CID [none]")
	}

	rulesetCID := string(*cid)

	matched, err := regexp.MatchString(config.RuleSetCIDRegex, rulesetCID)
	if err != nil {
		return nil, err
	}
	if !matched {
		return nil, fmt.Errorf("Invalid rule set CID [%s]", rulesetCID)
	}

	result, err := a.Get(rulesetCID)
	if err != nil {
		return nil, err
	}

	if a.Debug {
		a.Log.Printf("[DEBUG] fetch rule set, received JSON: %s", string(result))
	}

	ruleset := &RuleSet{}
	if err := json.Unmarshal(result, ruleset); err != nil {
		return nil, err
	}

	return ruleset, nil
}

// FetchRuleSets retrieves all rule sets available to API Token.
func (a *API) FetchRuleSets() (*[]RuleSet, error) {
	result, err := a.Get(config.RuleSetPrefix)
	if err != nil {
		return nil, err
	}

	var rulesets []RuleSet
	if err := json.Unmarshal(result, &rulesets); err != nil {
		return nil, err
	}

	return &rulesets, nil
}

// UpdateRuleSet updates passed rule set.
func (a *API) UpdateRuleSet(cfg *RuleSet) (*RuleSet, error) {
	if cfg == nil {
		return nil, fmt.Errorf("Invalid rule set config [nil]")
	}

	rulesetCID := string(cfg.CID)

	matched, err := regexp.MatchString(config.RuleSetCIDRegex, rulesetCID)
	if err != nil {
		return nil, err
	}
	if !matched {
		return nil, fmt.Errorf("Invalid rule set CID [%s]", rulesetCID)
	}

	jsonCfg, err := json.Marshal(cfg)
	if err != nil {
		return nil, err
	}

	if a.Debug {
		a.Log.Printf("[DEBUG] update rule set, sending JSON: %s", string(jsonCfg))
	}

	result, err := a.Put(rulesetCID, jsonCfg)
	if err != nil {
		return nil, err
	}

	ruleset := &RuleSet{}
	if err := json.Unmarshal(result, ruleset); err != nil {
		return nil, err
	}

	return ruleset, nil
}

// CreateRuleSet creates a new rule set.
func (a *API) CreateRuleSet(cfg *RuleSet) (*RuleSet, error) {
	if cfg == nil {
		return nil, fmt.Errorf("Invalid rule set config [nil]")
	}

	jsonCfg, err := json.Marshal(cfg)
	if err != nil {
		return nil, err
	}

	if a.Debug {
		a.Log.Printf("[DEBUG] create rule set, sending JSON: %s", string(jsonCfg))
	}

	resp, err := a.Post(config.RuleSetPrefix, jsonCfg)
	if err != nil {
		return nil, err
	}

	ruleset := &RuleSet{}
	if err := json.Unmarshal(resp, ruleset); err != nil {
		return nil, err
	}

	return ruleset, nil
}

// DeleteRuleSet deletes passed rule set.
func (a *API) DeleteRuleSet(cfg *RuleSet) (bool, error) {
	if cfg == nil {
		return false, fmt.Errorf("Invalid rule set config [nil]")
	}
	return a.DeleteRuleSetByCID(CIDType(&cfg.CID))
}

// DeleteRuleSetByCID deletes rule set with passed cid.
func (a *API) DeleteRuleSetByCID(cid CIDType) (bool, error) {
	if cid == nil || *cid == "" {
		return false, fmt.Errorf("Invalid rule set CID [none]")
	}

	rulesetCID := string(*cid)

	matched, err := regexp.MatchString(config.RuleSetCIDRegex, rulesetCID)
	if err != nil {
		return false, err
	}
	if !matched {
		return false, fmt.Errorf("Invalid rule set CID [%s]", rulesetCID)
	}

	_, err = a.Delete(rulesetCID)
	if err != nil {
		return false, err
	}

	return true, nil
}

// SearchRuleSets returns rule sets matching the specified search
// query and/or filter. If nil is passed for both parameters all
// rule sets will be returned.
func (a *API) SearchRuleSets(searchCriteria *SearchQueryType, filterCriteria *SearchFilterType) (*[]RuleSet, error) {
	q := url.Values{}

	if searchCriteria != nil && *searchCriteria != "" {
		q.Set("search", string(*searchCriteria))
	}

	if filterCriteria != nil && len(*filterCriteria) > 0 {
		for filter, criteria := range *filterCriteria {
			for _, val := range criteria {
				q.Add(filter, val)
			}
		}
	}

	if q.Encode() == "" {
		return a.FetchRuleSets()
	}

	reqURL := url.URL{
		Path:     config.RuleSetPrefix,
		RawQuery: q.Encode(),
	}

	result, err := a.Get(reqURL.String())
	if err != nil {
		return nil, fmt.Errorf("[ERROR] API call error %+v", err)
	}

	var rulesets []RuleSet
	if err := json.Unmarshal(result, &rulesets); err != nil {
		return nil, err
	}

	return &rulesets, nil
}
<commit_msg>Change `Value` to be of type `interface{}`.<commit_after>// Copyright 2016 Circonus, Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Rule Set API support - Fetch, Create, Update, Delete, and Search
// See: https://login.circonus.com/resources/api/calls/rule_set

package api

import (
	"encoding/json"
	"fmt"
	"net/url"
	"regexp"

	"github.com/circonus-labs/circonus-gometrics/api/config"
)

// RuleSetRule defines a ruleset rule
type RuleSetRule struct {
	Criteria          string      `json:"criteria"`                     // string
	Severity          uint        `json:"severity"`                     // uint
	Value             interface{} `json:"value"`                        // string when the metric type is text, float64 or int when the value is numeric.
	Wait              uint        `json:"wait"`                         // uint
	WindowingDuration uint        `json:"windowing_duration,omitempty"` // uint
	WindowingFunction *string     `json:"windowing_function,omitempty"` // string or null
}

// RuleSet defines a ruleset. See https://login.circonus.com/resources/api/calls/rule_set for more information.
type RuleSet struct {
	CheckCID      string             `json:"check"`            // string
	CID           string             `json:"_cid,omitempty"`   // string
	ContactGroups map[uint8][]string `json:"contact_groups"`   // [] len 5
	Derive        *string            `json:"derive,omitempty"` // string or null
	Link          *string            `json:"link"`             // string or null
	MetricName    string             `json:"metric_name"`      // string
	MetricTags    []string           `json:"metric_tags"`      // [] len >= 0
	MetricType    string             `json:"metric_type"`      // string
	Notes         *string            `json:"notes"`            // string or null
	Parent        *string            `json:"parent,omitempty"` // string or null
	Rules         []RuleSetRule      `json:"rules"`            // [] len >= 1
	Tags          []string           `json:"tags"`             // [] len >= 0
}

// NewRuleSet returns a new RuleSet (with defaults if applicable)
func NewRuleSet() *RuleSet {
	return &RuleSet{}
}

// FetchRuleSet retrieves rule set with passed cid.
func (a *API) FetchRuleSet(cid CIDType) (*RuleSet, error) {
	if cid == nil || *cid == "" {
		return nil, fmt.Errorf("Invalid rule set CID [none]")
	}

	rulesetCID := string(*cid)

	matched, err := regexp.MatchString(config.RuleSetCIDRegex, rulesetCID)
	if err != nil {
		return nil, err
	}
	if !matched {
		return nil, fmt.Errorf("Invalid rule set CID [%s]", rulesetCID)
	}

	result, err := a.Get(rulesetCID)
	if err != nil {
		return nil, err
	}

	if a.Debug {
		a.Log.Printf("[DEBUG] fetch rule set, received JSON: %s", string(result))
	}

	ruleset := &RuleSet{}
	if err := json.Unmarshal(result, ruleset); err != nil {
		return nil, err
	}

	return ruleset, nil
}

// FetchRuleSets retrieves all rule sets available to API Token.
func (a *API) FetchRuleSets() (*[]RuleSet, error) {
	result, err := a.Get(config.RuleSetPrefix)
	if err != nil {
		return nil, err
	}

	var rulesets []RuleSet
	if err := json.Unmarshal(result, &rulesets); err != nil {
		return nil, err
	}

	return &rulesets, nil
}

// UpdateRuleSet updates passed rule set.
func (a *API) UpdateRuleSet(cfg *RuleSet) (*RuleSet, error) {
	if cfg == nil {
		return nil, fmt.Errorf("Invalid rule set config [nil]")
	}

	rulesetCID := string(cfg.CID)

	matched, err := regexp.MatchString(config.RuleSetCIDRegex, rulesetCID)
	if err != nil {
		return nil, err
	}
	if !matched {
		return nil, fmt.Errorf("Invalid rule set CID [%s]", rulesetCID)
	}

	jsonCfg, err := json.Marshal(cfg)
	if err != nil {
		return nil, err
	}

	if a.Debug {
		a.Log.Printf("[DEBUG] update rule set, sending JSON: %s", string(jsonCfg))
	}

	result, err := a.Put(rulesetCID, jsonCfg)
	if err != nil {
		return nil, err
	}

	ruleset := &RuleSet{}
	if err := json.Unmarshal(result, ruleset); err != nil {
		return nil, err
	}

	return ruleset, nil
}

// CreateRuleSet creates a new rule set.
func (a *API) CreateRuleSet(cfg *RuleSet) (*RuleSet, error) {
	if cfg == nil {
		return nil, fmt.Errorf("Invalid rule set config [nil]")
	}

	jsonCfg, err := json.Marshal(cfg)
	if err != nil {
		return nil, err
	}

	if a.Debug {
		a.Log.Printf("[DEBUG] create rule set, sending JSON: %s", string(jsonCfg))
	}

	resp, err := a.Post(config.RuleSetPrefix, jsonCfg)
	if err != nil {
		return nil, err
	}

	ruleset := &RuleSet{}
	if err := json.Unmarshal(resp, ruleset); err != nil {
		return nil, err
	}

	return ruleset, nil
}

// DeleteRuleSet deletes passed rule set.
func (a *API) DeleteRuleSet(cfg *RuleSet) (bool, error) {
	if cfg == nil {
		return false, fmt.Errorf("Invalid rule set config [nil]")
	}
	return a.DeleteRuleSetByCID(CIDType(&cfg.CID))
}

// DeleteRuleSetByCID deletes rule set with passed cid.
func (a *API) DeleteRuleSetByCID(cid CIDType) (bool, error) {
	if cid == nil || *cid == "" {
		return false, fmt.Errorf("Invalid rule set CID [none]")
	}

	rulesetCID := string(*cid)

	matched, err := regexp.MatchString(config.RuleSetCIDRegex, rulesetCID)
	if err != nil {
		return false, err
	}
	if !matched {
		return false, fmt.Errorf("Invalid rule set CID [%s]", rulesetCID)
	}

	_, err = a.Delete(rulesetCID)
	if err != nil {
		return false, err
	}

	return true, nil
}

// SearchRuleSets returns rule sets matching the specified search
// query and/or filter. If nil is passed for both parameters all
// rule sets will be returned.
func (a *API) SearchRuleSets(searchCriteria *SearchQueryType, filterCriteria *SearchFilterType) (*[]RuleSet, error) {
	q := url.Values{}

	if searchCriteria != nil && *searchCriteria != "" {
		q.Set("search", string(*searchCriteria))
	}

	if filterCriteria != nil && len(*filterCriteria) > 0 {
		for filter, criteria := range *filterCriteria {
			for _, val := range criteria {
				q.Add(filter, val)
			}
		}
	}

	if q.Encode() == "" {
		return a.FetchRuleSets()
	}

	reqURL := url.URL{
		Path:     config.RuleSetPrefix,
		RawQuery: q.Encode(),
	}

	result, err := a.Get(reqURL.String())
	if err != nil {
		return nil, fmt.Errorf("[ERROR] API call error %+v", err)
	}

	var rulesets []RuleSet
	if err := json.Unmarshal(result, &rulesets); err != nil {
		return nil, err
	}

	return &rulesets, nil
}
<|endoftext|>


<commit_before>package api

import (
	"io"
	"io/ioutil"
)

// ListTestCases returns a list of test cases
func (c *Client) ListTestCases(organization string) (bool, []byte, error) {
	path := "/organisations/" + organization + "/test_cases"

	return c.fetch(path)
}

// TestCaseValidate will send a test case definition (JS) to the API
// to validate.
func (c *Client) TestCaseValidate(organization string, fileName string, data io.Reader) (bool, string, error) {
	// TODO how to pass options here?
	//      defining a struct maybe, but where?
	//      finally: add options here
	extraParams := map[string]string{
		"organisation_uid": organization,
	}

	req, err := fileUploadRequest(c.APIEndpoint+"/test_cases/validate", "POST", extraParams, "test_case[javascript_definition]", fileName, "application/javascript", data)
	if err != nil {
		return false, "", err
	}

	response, err := c.doRequestRaw(req)
	if err != nil {
		return false, "", err
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return false, "", err
	}

	defer response.Body.Close()

	if response.StatusCode != 200 {
		return false, string(body), nil
	}

	return true, string(body), nil
}

// TestCaseCreate will send a test case definition (JS) to the API
// to create it.
func (c *Client) TestCaseCreate(organization string, testCaseName string, fileName string, data io.Reader) (bool, string, error) {
	// TODO how to pass options here?
	//      defining a struct maybe, but where?
	//      finally: add options here
	extraParams := map[string]string{
		"test_case[name]": testCaseName,
	}

	req, err := fileUploadRequest(c.APIEndpoint+"/organisations/"+organization+"/test_cases", "POST", extraParams, "test_case[javascript_definition]", fileName, "application/javascript", data)
	if err != nil {
		return false, "", err
	}

	response, err := c.doRequestRaw(req)
	if err != nil {
		return false, "", err
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return false, "", err
	}

	defer response.Body.Close()

	return false, string(body), nil
}

// TestCaseUpdate will send a test case definition (JS) to the API
// to update an existing test case it.
func (c *Client) TestCaseUpdate(testCaseUID string, fileName string, data io.Reader) (bool, string, error) {
	// TODO how to pass options here?
	//      defining a struct maybe, but where?
	//      finally: add options here
	extraParams := map[string]string{}

	req, err := fileUploadRequest(c.APIEndpoint+"/test_cases/"+testCaseUID, "PATCH", extraParams, "test_case[javascript_definition]", fileName, "application/javascript", data)
	if err != nil {
		return false, "", err
	}

	response, err := c.doRequestRaw(req)
	if err != nil {
		return false, "", err
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return false, "", err
	}

	defer response.Body.Close()

	return true, string(body), nil
}

// DownloadTestCaseDefinition returns the JS definition
// of a given test case
func (c *Client) DownloadTestCaseDefinition(uid string) (bool, []byte, error) {
	path := "/test_cases/" + uid + "/download"

	return c.fetch(path)
}
<commit_msg>Report success if test case created (#36)<commit_after>package api

import (
	"io"
	"io/ioutil"
)

// ListTestCases returns a list of test cases
func (c *Client) ListTestCases(organization string) (bool, []byte, error) {
	path := "/organisations/" + organization + "/test_cases"

	return c.fetch(path)
}

// TestCaseValidate will send a test case definition (JS) to the API
// to validate.
func (c *Client) TestCaseValidate(organization string, fileName string, data io.Reader) (bool, string, error) {
	// TODO how to pass options here?
	//      defining a struct maybe, but where?
	//      finally: add options here
	extraParams := map[string]string{
		"organisation_uid": organization,
	}

	req, err := fileUploadRequest(c.APIEndpoint+"/test_cases/validate", "POST", extraParams, "test_case[javascript_definition]", fileName, "application/javascript", data)
	if err != nil {
		return false, "", err
	}

	response, err := c.doRequestRaw(req)
	if err != nil {
		return false, "", err
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return false, "", err
	}

	defer response.Body.Close()

	if response.StatusCode != 200 {
		return false, string(body), nil
	}

	return true, string(body), nil
}

// TestCaseCreate will send a test case definition (JS) to the API
// to create it.
func (c *Client) TestCaseCreate(organization string, testCaseName string, fileName string, data io.Reader) (bool, string, error) {
	// TODO how to pass options here?
	//      defining a struct maybe, but where?
	//      finally: add options here
	extraParams := map[string]string{
		"test_case[name]": testCaseName,
	}

	req, err := fileUploadRequest(c.APIEndpoint+"/organisations/"+organization+"/test_cases", "POST", extraParams, "test_case[javascript_definition]", fileName, "application/javascript", data)
	if err != nil {
		return false, "", err
	}

	response, err := c.doRequestRaw(req)
	if err != nil {
		return false, "", err
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return false, "", err
	}

	defer response.Body.Close()

	return true, string(body), nil
}

// TestCaseUpdate will send a test case definition (JS) to the API
// to update an existing test case it.
func (c *Client) TestCaseUpdate(testCaseUID string, fileName string, data io.Reader) (bool, string, error) {
	// TODO how to pass options here?
	//      defining a struct maybe, but where?
	//      finally: add options here
	extraParams := map[string]string{}

	req, err := fileUploadRequest(c.APIEndpoint+"/test_cases/"+testCaseUID, "PATCH", extraParams, "test_case[javascript_definition]", fileName, "application/javascript", data)
	if err != nil {
		return false, "", err
	}

	response, err := c.doRequestRaw(req)
	if err != nil {
		return false, "", err
	}

	body, err := ioutil.ReadAll(response.Body)
	if err != nil {
		return false, "", err
	}

	defer response.Body.Close()

	return true, string(body), nil
}

// DownloadTestCaseDefinition returns the JS definition
// of a given test case
func (c *Client) DownloadTestCaseDefinition(uid string) (bool, []byte, error) {
	path := "/test_cases/" + uid + "/download"

	return c.fetch(path)
}
<|endoftext|>


<commit_before>package alm

import (
	"errors"
	"fmt"

	log "github.com/sirupsen/logrus"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/cache"

	"github.com/coreos-inc/alm/apis/clusterserviceversion/v1alpha1"
	"github.com/coreos-inc/alm/client"
	"github.com/coreos-inc/alm/config"
	"github.com/coreos-inc/alm/install"
	"github.com/coreos-inc/alm/queueinformer"
)

var ErrRequirementsNotMet = errors.New("requirements were not met")

type ALMOperator struct {
	*queueinformer.Operator
	restClient *rest.RESTClient
}

func NewALMOperator(kubeconfig string, cfg *config.Config) (*ALMOperator, error) {
	csvClient, err := client.NewClusterServiceVersionClient(kubeconfig)
	if err != nil {
		return nil, err
	}

	csvWatchers := []*cache.ListWatch{}
	for _, namespace := range cfg.Namespaces {
		csvWatcher := cache.NewListWatchFromClient(
			csvClient,
			"clusterserviceversion-v1s",
			namespace,
			fields.Everything(),
		)
		csvWatchers = append(csvWatchers, csvWatcher)
	}

	sharedIndexInformers := []cache.SharedIndexInformer{}
	for _, csvWatcher := range csvWatchers {
		csvInformer := cache.NewSharedIndexInformer(
			csvWatcher,
			&v1alpha1.ClusterServiceVersion{},
			cfg.Interval,
			cache.Indexers{},
		)
		sharedIndexInformers = append(sharedIndexInformers, csvInformer)
	}

	queueOperator, err := queueinformer.NewOperator(kubeconfig)
	if err != nil {
		return nil, err
	}

	op := &ALMOperator{
		queueOperator,
		csvClient,
	}
	csvQueueInformers := queueinformer.New(
		"operatorversions",
		sharedIndexInformers,
		op.syncClusterServiceVersion,
		nil,
	)
	for _, opVerQueueInformer := range csvQueueInformers {
		op.RegisterQueueInformer(opVerQueueInformer)
	}

	return op, nil
}

func (a *ALMOperator) syncClusterServiceVersion(obj interface{}) error {
	clusterServiceVersion, ok := obj.(*v1alpha1.ClusterServiceVersion)
	if !ok {
		log.Debugf("wrong type: %#v", obj)
		return fmt.Errorf("casting ClusterServiceVersion failed")
	}

	log.Infof("syncing ClusterServiceVersion: %s", clusterServiceVersion.SelfLink)

	resolver := install.NewStrategyResolver(
		a.OpClient,
		clusterServiceVersion.ObjectMeta,
		clusterServiceVersion.TypeMeta,
	)
	ok, err := requirementsMet(clusterServiceVersion.Spec.CustomResourceDefinitions, a.restClient)
	if err != nil {
		return err
	}
	if !ok {
		log.Info("requirements were not met: %v", clusterServiceVersion.Spec.CustomResourceDefinitions)
		return ErrRequirementsNotMet
	}
	err = resolver.ApplyStrategy(&clusterServiceVersion.Spec.InstallStrategy)
	if err != nil {
		return err
	}

	log.Infof(
		"%s install strategy successful for %s",
		clusterServiceVersion.Spec.InstallStrategy.StrategyName,
		clusterServiceVersion.SelfLink,
	)
	return nil
}

func requirementsMet(crds v1alpha1.CustomResourceDefinitions, kubeClient *rest.RESTClient) (bool, error) {
	// Build a set of the required CRDs.
	requiredCRDSet := map[string]struct{}{}
	for _, crd := range crds.Owned {
		requiredCRDSet[crd] = struct{}{}
	}
	for _, crd := range crds.Required {
		requiredCRDSet[crd] = struct{}{}
	}

	for crd := range requiredCRDSet {
		result := kubeClient.Get().Namespace("").Name(crd).Resource("customresourcedefinition").Do()
		if result.Error() != nil {
			log.Info("Namespace, name, or kind was not met")
			return false, nil
		}
	}
	log.Info("Successfully met all requirements")
	return true, nil
}
<commit_msg>Look for requirements in same namespace as ClusterServiceVersion is defined<commit_after>package alm

import (
	"errors"
	"fmt"

	log "github.com/sirupsen/logrus"
	"k8s.io/apimachinery/pkg/fields"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/cache"

	"github.com/coreos-inc/alm/apis/clusterserviceversion/v1alpha1"
	"github.com/coreos-inc/alm/client"
	"github.com/coreos-inc/alm/config"
	"github.com/coreos-inc/alm/install"
	"github.com/coreos-inc/alm/queueinformer"
)

var ErrRequirementsNotMet = errors.New("requirements were not met")

type ALMOperator struct {
	*queueinformer.Operator
	restClient *rest.RESTClient
}

func NewALMOperator(kubeconfig string, cfg *config.Config) (*ALMOperator, error) {
	csvClient, err := client.NewClusterServiceVersionClient(kubeconfig)
	if err != nil {
		return nil, err
	}

	csvWatchers := []*cache.ListWatch{}
	for _, namespace := range cfg.Namespaces {
		csvWatcher := cache.NewListWatchFromClient(
			csvClient,
			"clusterserviceversion-v1s",
			namespace,
			fields.Everything(),
		)
		csvWatchers = append(csvWatchers, csvWatcher)
	}

	sharedIndexInformers := []cache.SharedIndexInformer{}
	for _, csvWatcher := range csvWatchers {
		csvInformer := cache.NewSharedIndexInformer(
			csvWatcher,
			&v1alpha1.ClusterServiceVersion{},
			cfg.Interval,
			cache.Indexers{},
		)
		sharedIndexInformers = append(sharedIndexInformers, csvInformer)
	}

	queueOperator, err := queueinformer.NewOperator(kubeconfig)
	if err != nil {
		return nil, err
	}

	op := &ALMOperator{
		queueOperator,
		csvClient,
	}
	csvQueueInformers := queueinformer.New(
		"operatorversions",
		sharedIndexInformers,
		op.syncClusterServiceVersion,
		nil,
	)
	for _, opVerQueueInformer := range csvQueueInformers {
		op.RegisterQueueInformer(opVerQueueInformer)
	}

	return op, nil
}

func (a *ALMOperator) syncClusterServiceVersion(obj interface{}) error {
	clusterServiceVersion, ok := obj.(*v1alpha1.ClusterServiceVersion)
	if !ok {
		log.Debugf("wrong type: %#v", obj)
		return fmt.Errorf("casting ClusterServiceVersion failed")
	}

	log.Infof("syncing ClusterServiceVersion: %s", clusterServiceVersion.SelfLink)

	resolver := install.NewStrategyResolver(
		a.OpClient,
		clusterServiceVersion.ObjectMeta,
		clusterServiceVersion.TypeMeta,
	)
	ok, err := requirementsMet(clusterServiceVersion.Spec.CustomResourceDefinitions, a.restClient)

	if err != nil {
		return err
	}
	if !ok {
		log.Info("requirements were not met: %v", clusterServiceVersion.Spec.CustomResourceDefinitions)
		return ErrRequirementsNotMet
	}
	err = resolver.ApplyStrategy(&clusterServiceVersion.Spec.InstallStrategy)
	if err != nil {
		return err
	}

	log.Infof(
		"%s install strategy successful for %s",
		clusterServiceVersion.Spec.InstallStrategy.StrategyName,
		clusterServiceVersion.SelfLink,
	)
	return nil
}

func requirementsMet(namespace string, requirements []v1alpha1.Requirements, kubeClient *rest.RESTClient) (bool, error) {
	for _, element := range requirements {
		if element.Optional {
			log.Info("Requirement was optional")
			continue
		}
		result := kubeClient.Get().Namespace(namespace).Name(element.Name).Resource(element.Kind).Do()
		if result.Error() != nil {
			log.Infof("Namespace, name, or kind was not met: %s", result.Error())
			return false, nil
		}

	}
	log.Info("Successfully met all requirements")
	return true, nil
}
<|endoftext|>