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

package client

import (
	"context"
	"fmt"
	"sort"
	"strings"
	"time"

	"github.com/tsuru/gnuflag"
	"github.com/tsuru/go-tsuruclient/pkg/client"
	"github.com/tsuru/go-tsuruclient/pkg/tsuru"
	"github.com/tsuru/tsuru-client/tsuru/formatter"
	"github.com/tsuru/tsuru/cmd"
)

type TokenCreateCmd struct {
	fs      *gnuflag.FlagSet
	args    tsuru.TeamTokenCreateArgs
	expires time.Duration
}

func (c *TokenCreateCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "token-create",
		Usage:   "token-create [--id/-i token-id] [--team/-t team] [--description/-d description] [--expires/-e expiration]",
		Desc:    `Creates a new API token associated to a team.`,
		MinArgs: 0,
	}
}

func (c *TokenCreateCmd) Run(ctx *cmd.Context, cli *cmd.Client) error {
	apiClient, err := client.ClientFromEnvironment(&tsuru.Configuration{
		HTTPClient: cli.HTTPClient,
	})
	if err != nil {
		return err
	}
	c.args.ExpiresIn = int64(c.expires / time.Second)
	token, _, err := apiClient.AuthApi.TeamTokenCreate(context.TODO(), c.args)
	if err != nil {
		return err
	}
	fmt.Fprintf(ctx.Stdout, "Token %q created: %s\n", token.TokenId, token.Token)
	return nil
}

func (c *TokenCreateCmd) Flags() *gnuflag.FlagSet {
	if c.fs == nil {
		c.fs = gnuflag.NewFlagSet("", gnuflag.ExitOnError)

		description := "A description on how the token will be used."
		c.fs.StringVar(&c.args.Description, "description", "", description)
		c.fs.StringVar(&c.args.Description, "d", "", description)

		tokenID := "A unique identifier for the token being created."
		c.fs.StringVar(&c.args.TokenId, "id", "", tokenID)
		c.fs.StringVar(&c.args.TokenId, "i", "", tokenID)

		team := "The team name responsible for this token."
		c.fs.StringVar(&c.args.Team, "team", "", team)
		c.fs.StringVar(&c.args.Team, "t", "", team)

		expiration := "The expiration for the token being created. A duration suffix is mandatory (s for seconds, m for minutes, h for hours, ...). 0 or unset means it never expires."
		c.fs.DurationVar(&c.expires, "expires", 0, expiration)
		c.fs.DurationVar(&c.expires, "e", 0, expiration)
	}
	return c.fs
}

type TokenUpdateCmd struct {
	fs      *gnuflag.FlagSet
	args    tsuru.TeamTokenUpdateArgs
	expires time.Duration
}

func (c *TokenUpdateCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "token-update",
		Usage:   "token-update <token-id> [--regenerate] [--description/-d description] [--expires/-e expiration]",
		Desc:    `Creates a new API token associated to a team.`,
		MinArgs: 1,
	}
}

func (c *TokenUpdateCmd) Run(ctx *cmd.Context, cli *cmd.Client) error {
	apiClient, err := client.ClientFromEnvironment(&tsuru.Configuration{
		HTTPClient: cli.HTTPClient,
	})
	if err != nil {
		return err
	}
	c.args.ExpiresIn = int64(c.expires / time.Second)
	token, _, err := apiClient.AuthApi.TeamTokenUpdate(context.TODO(), ctx.Args[0], c.args)
	if err != nil {
		return err
	}
	fmt.Fprintf(ctx.Stdout, "Token %q updated: %s\n", token.TokenId, token.Token)
	return nil
}

func (c *TokenUpdateCmd) Flags() *gnuflag.FlagSet {
	if c.fs == nil {
		c.fs = gnuflag.NewFlagSet("", gnuflag.ExitOnError)

		description := "A description on how the token will be used."
		c.fs.StringVar(&c.args.Description, "description", "", description)
		c.fs.StringVar(&c.args.Description, "d", "", description)

		regenerate := "Setting regenerate will change de value of the token, invalidating the previous value."
		c.fs.BoolVar(&c.args.Regenerate, "regenerate", false, regenerate)

		expiration := "The expiration for the token being updated. A duration suffix is mandatory ('s' for seconds, 'm' for minutes, 'h' for hours, ...). Setting to 0 or unset means the previous value will be used. Setting to a negative value will remove any existing expiration."
		c.fs.DurationVar(&c.expires, "expires", 0, expiration)
		c.fs.DurationVar(&c.expires, "e", 0, expiration)
	}
	return c.fs
}

type TokenListCmd struct {
}

func (c *TokenListCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "token-list",
		Usage:   "token-list",
		Desc:    `List existing API tokens associated with a team.`,
		MinArgs: 0,
	}
}

func (c *TokenListCmd) Run(ctx *cmd.Context, cli *cmd.Client) error {
	apiClient, err := client.ClientFromEnvironment(&tsuru.Configuration{
		HTTPClient: cli.HTTPClient,
	})
	if err != nil {
		return err
	}
	tokens, _, err := apiClient.AuthApi.TeamTokensList(context.TODO())
	if err != nil {
		return err
	}
	table := cmd.Table{
		Headers:       cmd.Row{"Token ID", "Team", "Description", "Creator", "Timestamps", "Value", "Roles"},
		LineSeparator: true,
	}
	for _, t := range tokens {
		if t.Token == "" {
			t.Token = "Not authorized"
		}
		table.AddRow(cmd.Row{
			t.TokenId,
			t.Team,
			t.Description,
			t.CreatorEmail,
			fmt.Sprintf(" Created At: %s\n Expires At: %s\nLast Access: %s",
				formatter.FormatDate(t.CreatedAt),
				formatter.FormatDate(t.ExpiresAt),
				formatter.FormatDate(t.LastAccess),
			),
			t.Token,
			formatRoles(t.Roles),
		})
	}
	table.Sort()
	fmt.Fprint(ctx.Stdout, table.String())
	return nil
}

func formatRoles(roles []tsuru.RoleInstance) string {
	rolesStr := make([]string, len(roles))
	for i, r := range roles {
		rolesStr[i] = fmt.Sprintf("%s(%s)", r.Name, r.Contextvalue)
	}
	sort.Strings(rolesStr)
	return strings.Join(rolesStr, "\n")
}

type TokenDeleteCmd struct {
}

func (c *TokenDeleteCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "token-delete",
		Usage:   "token-delete <token id>",
		Desc:    `Delete an existing token.`,
		MinArgs: 1,
	}
}

func (c *TokenDeleteCmd) Run(ctx *cmd.Context, cli *cmd.Client) error {
	apiClient, err := client.ClientFromEnvironment(&tsuru.Configuration{
		HTTPClient: cli.HTTPClient,
	})
	if err != nil {
		return err
	}
	_, err = apiClient.AuthApi.TeamTokenDelete(context.TODO(), ctx.Args[0])
	if err != nil {
		return err
	}
	fmt.Fprintln(ctx.Stdout, "Token successfully deleted.")
	return nil
}
<commit_msg>client: use tablecli.{Table,Row} instead of cmd.{Table,Row}<commit_after>// Copyright 2018 tsuru authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package client

import (
	"context"
	"fmt"
	"sort"
	"strings"
	"time"

	"github.com/tsuru/tablecli"

	"github.com/tsuru/gnuflag"
	"github.com/tsuru/go-tsuruclient/pkg/client"
	"github.com/tsuru/go-tsuruclient/pkg/tsuru"
	"github.com/tsuru/tsuru-client/tsuru/formatter"
	"github.com/tsuru/tsuru/cmd"
)

type TokenCreateCmd struct {
	fs      *gnuflag.FlagSet
	args    tsuru.TeamTokenCreateArgs
	expires time.Duration
}

func (c *TokenCreateCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "token-create",
		Usage:   "token-create [--id/-i token-id] [--team/-t team] [--description/-d description] [--expires/-e expiration]",
		Desc:    `Creates a new API token associated to a team.`,
		MinArgs: 0,
	}
}

func (c *TokenCreateCmd) Run(ctx *cmd.Context, cli *cmd.Client) error {
	apiClient, err := client.ClientFromEnvironment(&tsuru.Configuration{
		HTTPClient: cli.HTTPClient,
	})
	if err != nil {
		return err
	}
	c.args.ExpiresIn = int64(c.expires / time.Second)
	token, _, err := apiClient.AuthApi.TeamTokenCreate(context.TODO(), c.args)
	if err != nil {
		return err
	}
	fmt.Fprintf(ctx.Stdout, "Token %q created: %s\n", token.TokenId, token.Token)
	return nil
}

func (c *TokenCreateCmd) Flags() *gnuflag.FlagSet {
	if c.fs == nil {
		c.fs = gnuflag.NewFlagSet("", gnuflag.ExitOnError)

		description := "A description on how the token will be used."
		c.fs.StringVar(&c.args.Description, "description", "", description)
		c.fs.StringVar(&c.args.Description, "d", "", description)

		tokenID := "A unique identifier for the token being created."
		c.fs.StringVar(&c.args.TokenId, "id", "", tokenID)
		c.fs.StringVar(&c.args.TokenId, "i", "", tokenID)

		team := "The team name responsible for this token."
		c.fs.StringVar(&c.args.Team, "team", "", team)
		c.fs.StringVar(&c.args.Team, "t", "", team)

		expiration := "The expiration for the token being created. A duration suffix is mandatory (s for seconds, m for minutes, h for hours, ...). 0 or unset means it never expires."
		c.fs.DurationVar(&c.expires, "expires", 0, expiration)
		c.fs.DurationVar(&c.expires, "e", 0, expiration)
	}
	return c.fs
}

type TokenUpdateCmd struct {
	fs      *gnuflag.FlagSet
	args    tsuru.TeamTokenUpdateArgs
	expires time.Duration
}

func (c *TokenUpdateCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "token-update",
		Usage:   "token-update <token-id> [--regenerate] [--description/-d description] [--expires/-e expiration]",
		Desc:    `Creates a new API token associated to a team.`,
		MinArgs: 1,
	}
}

func (c *TokenUpdateCmd) Run(ctx *cmd.Context, cli *cmd.Client) error {
	apiClient, err := client.ClientFromEnvironment(&tsuru.Configuration{
		HTTPClient: cli.HTTPClient,
	})
	if err != nil {
		return err
	}
	c.args.ExpiresIn = int64(c.expires / time.Second)
	token, _, err := apiClient.AuthApi.TeamTokenUpdate(context.TODO(), ctx.Args[0], c.args)
	if err != nil {
		return err
	}
	fmt.Fprintf(ctx.Stdout, "Token %q updated: %s\n", token.TokenId, token.Token)
	return nil
}

func (c *TokenUpdateCmd) Flags() *gnuflag.FlagSet {
	if c.fs == nil {
		c.fs = gnuflag.NewFlagSet("", gnuflag.ExitOnError)

		description := "A description on how the token will be used."
		c.fs.StringVar(&c.args.Description, "description", "", description)
		c.fs.StringVar(&c.args.Description, "d", "", description)

		regenerate := "Setting regenerate will change de value of the token, invalidating the previous value."
		c.fs.BoolVar(&c.args.Regenerate, "regenerate", false, regenerate)

		expiration := "The expiration for the token being updated. A duration suffix is mandatory ('s' for seconds, 'm' for minutes, 'h' for hours, ...). Setting to 0 or unset means the previous value will be used. Setting to a negative value will remove any existing expiration."
		c.fs.DurationVar(&c.expires, "expires", 0, expiration)
		c.fs.DurationVar(&c.expires, "e", 0, expiration)
	}
	return c.fs
}

type TokenListCmd struct {
}

func (c *TokenListCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "token-list",
		Usage:   "token-list",
		Desc:    `List existing API tokens associated with a team.`,
		MinArgs: 0,
	}
}

func (c *TokenListCmd) Run(ctx *cmd.Context, cli *cmd.Client) error {
	apiClient, err := client.ClientFromEnvironment(&tsuru.Configuration{
		HTTPClient: cli.HTTPClient,
	})
	if err != nil {
		return err
	}
	tokens, _, err := apiClient.AuthApi.TeamTokensList(context.TODO())
	if err != nil {
		return err
	}
	table := tablecli.Table{
		Headers:       tablecli.Row{"Token ID", "Team", "Description", "Creator", "Timestamps", "Value", "Roles"},
		LineSeparator: true,
	}
	for _, t := range tokens {
		if t.Token == "" {
			t.Token = "Not authorized"
		}
		table.AddRow(tablecli.Row{
			t.TokenId,
			t.Team,
			t.Description,
			t.CreatorEmail,
			fmt.Sprintf(" Created At: %s\n Expires At: %s\nLast Access: %s",
				formatter.FormatDate(t.CreatedAt),
				formatter.FormatDate(t.ExpiresAt),
				formatter.FormatDate(t.LastAccess),
			),
			t.Token,
			formatRoles(t.Roles),
		})
	}
	table.Sort()
	fmt.Fprint(ctx.Stdout, table.String())
	return nil
}

func formatRoles(roles []tsuru.RoleInstance) string {
	rolesStr := make([]string, len(roles))
	for i, r := range roles {
		rolesStr[i] = fmt.Sprintf("%s(%s)", r.Name, r.Contextvalue)
	}
	sort.Strings(rolesStr)
	return strings.Join(rolesStr, "\n")
}

type TokenDeleteCmd struct {
}

func (c *TokenDeleteCmd) Info() *cmd.Info {
	return &cmd.Info{
		Name:    "token-delete",
		Usage:   "token-delete <token id>",
		Desc:    `Delete an existing token.`,
		MinArgs: 1,
	}
}

func (c *TokenDeleteCmd) Run(ctx *cmd.Context, cli *cmd.Client) error {
	apiClient, err := client.ClientFromEnvironment(&tsuru.Configuration{
		HTTPClient: cli.HTTPClient,
	})
	if err != nil {
		return err
	}
	_, err = apiClient.AuthApi.TeamTokenDelete(context.TODO(), ctx.Args[0])
	if err != nil {
		return err
	}
	fmt.Fprintln(ctx.Stdout, "Token successfully deleted.")
	return nil
}
<|endoftext|>


<commit_before>// Copyright 2013 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.

// This file implements printing of types.

package types

import (
	"bytes"
	"fmt"
	"unicode/utf8"
)

// A Qualifier controls how named package-level objects are printed in
// calls to TypeString, ObjectString, and SelectionString.
//
// These three formatting routines call the Qualifier for each
// package-level object O, and if the Qualifier returns a non-empty
// string p, the object is printed in the form p.O.
// If it returns an empty string, only the object name O is printed.
//
// Using a nil Qualifier is equivalent to using (*Package).Path: the
// object is qualified by the import path, e.g., "encoding/json.Marshal".
//
type Qualifier func(*Package) string

// RelativeTo returns a Qualifier that fully qualifies members of
// all packages other than pkg.
func RelativeTo(pkg *Package) Qualifier {
	if pkg == nil {
		return nil
	}
	return func(other *Package) string {
		if pkg == other {
			return "" // same package; unqualified
		}
		return other.Path()
	}
}

// If gcCompatibilityMode is set, printing of types is modified
// to match the representation of some types in the gc compiler:
//
//	- byte and rune lose their alias name and simply stand for
//	  uint8 and int32 respectively
//	- embedded interfaces get flattened (the embedding info is lost,
//	  and certain recursive interface types cannot be printed anymore)
//
// This makes it easier to compare packages computed with the type-
// checker vs packages imported from gc export data.
//
// Caution: This flag affects all uses of WriteType, globally.
// It is only provided for testing in conjunction with
// gc-generated data.
//
// This flag is exported in the x/tools/go/types package. We don't
// need it at the moment in the std repo and so we don't export it
// anymore. We should eventually try to remove it altogether.
// TODO(gri) remove this
var gcCompatibilityMode bool

// TypeString returns the string representation of typ.
// The Qualifier controls the printing of
// package-level objects, and may be nil.
func TypeString(typ Type, qf Qualifier) string {
	var buf bytes.Buffer
	WriteType(&buf, typ, qf)
	return buf.String()
}

// WriteType writes the string representation of typ to buf.
// The Qualifier controls the printing of
// package-level objects, and may be nil.
func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
	writeType(buf, typ, qf, make([]Type, 0, 8))
}

// instanceMarker is the prefix for an instantiated type
// in "non-evaluated" instance form.
const instanceMarker = '#'

func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
	// Theoretically, this is a quadratic lookup algorithm, but in
	// practice deeply nested composite types with unnamed component
	// types are uncommon. This code is likely more efficient than
	// using a map.
	for _, t := range visited {
		if t == typ {
			fmt.Fprintf(buf, "○%T", goTypeName(typ)) // cycle to typ
			return
		}
	}
	visited = append(visited, typ)

	switch t := typ.(type) {
	case nil:
		buf.WriteString("<nil>")

	case *Basic:
		if t.kind == UnsafePointer {
			buf.WriteString("unsafe.")
		}
		if gcCompatibilityMode {
			// forget the alias names
			switch t.kind {
			case Byte:
				t = Typ[Uint8]
			case Rune:
				t = Typ[Int32]
			}
		}
		buf.WriteString(t.name)

	case *Array:
		fmt.Fprintf(buf, "[%d]", t.len)
		writeType(buf, t.elem, qf, visited)

	case *Slice:
		buf.WriteString("[]")
		writeType(buf, t.elem, qf, visited)

	case *Struct:
		buf.WriteString("struct{")
		for i, f := range t.fields {
			if i > 0 {
				buf.WriteString("; ")
			}
			buf.WriteString(f.name)
			if f.embedded {
				// emphasize that the embedded field's name
				// doesn't match the field's type name
				if f.name != embeddedFieldName(f.typ) {
					buf.WriteString(" /* = ")
					writeType(buf, f.typ, qf, visited)
					buf.WriteString(" */")
				}
			} else {
				buf.WriteByte(' ')
				writeType(buf, f.typ, qf, visited)
			}
			if tag := t.Tag(i); tag != "" {
				fmt.Fprintf(buf, " %q", tag)
			}
		}
		buf.WriteByte('}')

	case *Pointer:
		buf.WriteByte('*')
		writeType(buf, t.base, qf, visited)

	case *Tuple:
		writeTuple(buf, t, false, qf, visited)

	case *Signature:
		buf.WriteString("func")
		writeSignature(buf, t, qf, visited)

	case *Sum:
		for i, t := range t.types {
			if i > 0 {
				buf.WriteString(", ")
			}
			writeType(buf, t, qf, visited)
		}

	case *Interface:
		// We write the source-level methods and embedded types rather
		// than the actual method set since resolved method signatures
		// may have non-printable cycles if parameters have embedded
		// interface types that (directly or indirectly) embed the
		// current interface. For instance, consider the result type
		// of m:
		//
		//     type T interface{
		//         m() interface{ T }
		//     }
		//
		buf.WriteString("interface{")
		empty := true
		if gcCompatibilityMode {
			// print flattened interface
			// (useful to compare against gc-generated interfaces)
			for i, m := range t.allMethods {
				if i > 0 {
					buf.WriteString("; ")
				}
				buf.WriteString(m.name)
				writeSignature(buf, m.typ.(*Signature), qf, visited)
				empty = false
			}
			if !empty && t.allTypes != nil {
				buf.WriteString("; ")
			}
			if t.allTypes != nil {
				buf.WriteString("type ")
				writeType(buf, t.allTypes, qf, visited)
			}
		} else {
			// print explicit interface methods and embedded types
			for i, m := range t.methods {
				if i > 0 {
					buf.WriteString("; ")
				}
				buf.WriteString(m.name)
				writeSignature(buf, m.typ.(*Signature), qf, visited)
				empty = false
			}
			if !empty && t.types != nil {
				buf.WriteString("; ")
			}
			if t.types != nil {
				buf.WriteString("type ")
				writeType(buf, t.types, qf, visited)
				empty = false
			}
			if !empty && len(t.embeddeds) > 0 {
				buf.WriteString("; ")
			}
			for i, typ := range t.embeddeds {
				if i > 0 {
					buf.WriteString("; ")
				}
				writeType(buf, typ, qf, visited)
				empty = false
			}
		}
		if t.allMethods == nil || len(t.methods) > len(t.allMethods) {
			if !empty {
				buf.WriteByte(' ')
			}
			buf.WriteString("/* incomplete */")
		}
		buf.WriteByte('}')

	case *Map:
		buf.WriteString("map[")
		writeType(buf, t.key, qf, visited)
		buf.WriteByte(']')
		writeType(buf, t.elem, qf, visited)

	case *Chan:
		var s string
		var parens bool
		switch t.dir {
		case SendRecv:
			s = "chan "
			// chan (<-chan T) requires parentheses
			if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
				parens = true
			}
		case SendOnly:
			s = "chan<- "
		case RecvOnly:
			s = "<-chan "
		default:
			panic("unreachable")
		}
		buf.WriteString(s)
		if parens {
			buf.WriteByte('(')
		}
		writeType(buf, t.elem, qf, visited)
		if parens {
			buf.WriteByte(')')
		}

	case *Named:
		writeTypeName(buf, t.obj, qf)
		if t.targs != nil {
			// instantiated type
			buf.WriteByte('[')
			writeTypeList(buf, t.targs, qf, visited)
			buf.WriteByte(']')
		} else if t.tparams != nil {
			// parameterized type
			writeTParamList(buf, t.tparams, qf, visited)
		}

	case *TypeParam:
		s := "?"
		if t.obj != nil {
			s = t.obj.name
		}
		buf.WriteString(s + subscript(t.id))

	case *instance:
		buf.WriteByte(instanceMarker) // indicate "non-evaluated" syntactic instance
		writeTypeName(buf, t.base.obj, qf)
		buf.WriteByte('[')
		writeTypeList(buf, t.targs, qf, visited)
		buf.WriteByte(']')

	case *bottom:
		buf.WriteString("⊥")

	case *top:
		buf.WriteString("⊤")

	default:
		// For externally defined implementations of Type.
		buf.WriteString(t.String())
	}
}

func writeTypeList(buf *bytes.Buffer, list []Type, qf Qualifier, visited []Type) {
	for i, typ := range list {
		if i > 0 {
			buf.WriteString(", ")
		}
		writeType(buf, typ, qf, visited)
	}
}

func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited []Type) {
	// TODO(rFindley) compare this with the corresponding implementation in types2
	buf.WriteString("[")
	var prev Type
	for i, p := range list {
		// TODO(rFindley) support 'any' sugar here.
		var b Type = &emptyInterface
		if t, _ := p.typ.(*TypeParam); t != nil && t.bound != nil {
			b = t.bound
		}
		if i > 0 {
			if b != prev {
				// type bound changed - write previous one before advancing
				buf.WriteByte(' ')
				writeType(buf, prev, qf, visited)
			}
			buf.WriteString(", ")
		}
		prev = b

		if t, _ := p.typ.(*TypeParam); t != nil {
			writeType(buf, t, qf, visited)
		} else {
			buf.WriteString(p.name)
		}
	}
	if prev != nil {
		buf.WriteByte(' ')
		writeType(buf, prev, qf, visited)
	}
	buf.WriteByte(']')
}

func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
	s := "<Named w/o object>"
	if obj != nil {
		if obj.pkg != nil {
			writePackage(buf, obj.pkg, qf)
		}
		// TODO(gri): function-local named types should be displayed
		// differently from named types at package level to avoid
		// ambiguity.
		s = obj.name
	}
	buf.WriteString(s)
}

func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
	buf.WriteByte('(')
	if tup != nil {
		for i, v := range tup.vars {
			if i > 0 {
				buf.WriteString(", ")
			}
			if v.name != "" {
				buf.WriteString(v.name)
				buf.WriteByte(' ')
			}
			typ := v.typ
			if variadic && i == len(tup.vars)-1 {
				if s, ok := typ.(*Slice); ok {
					buf.WriteString("...")
					typ = s.elem
				} else {
					// special case:
					// append(s, "foo"...) leads to signature func([]byte, string...)
					if t := asBasic(typ); t == nil || t.kind != String {
						panic("internal error: string type expected")
					}
					writeType(buf, typ, qf, visited)
					buf.WriteString("...")
					continue
				}
			}
			writeType(buf, typ, qf, visited)
		}
	}
	buf.WriteByte(')')
}

// WriteSignature writes the representation of the signature sig to buf,
// without a leading "func" keyword.
// The Qualifier controls the printing of
// package-level objects, and may be nil.
func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
	writeSignature(buf, sig, qf, make([]Type, 0, 8))
}

func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
	if sig.tparams != nil {
		writeTParamList(buf, sig.tparams, qf, visited)
	}

	writeTuple(buf, sig.params, sig.variadic, qf, visited)

	n := sig.results.Len()
	if n == 0 {
		// no result
		return
	}

	buf.WriteByte(' ')
	if n == 1 && sig.results.vars[0].name == "" {
		// single unnamed result
		writeType(buf, sig.results.vars[0].typ, qf, visited)
		return
	}

	// multiple or named result(s)
	writeTuple(buf, sig.results, false, qf, visited)
}

// embeddedFieldName returns an embedded field's name given its type.
// The result is "" if the type doesn't have an embedded field name.
func embeddedFieldName(typ Type) string {
	switch t := typ.(type) {
	case *Basic:
		return t.name
	case *Named:
		return t.obj.name
	case *Pointer:
		// *T is ok, but **T is not
		if _, ok := t.base.(*Pointer); !ok {
			return embeddedFieldName(t.base)
		}
	case *instance:
		return t.base.obj.name
	}
	return "" // not a (pointer to) a defined type
}

// subscript returns the decimal (utf8) representation of x using subscript digits.
func subscript(x uint64) string {
	const w = len("₀") // all digits 0...9 have the same utf8 width
	var buf [32 * w]byte
	i := len(buf)
	for {
		i -= w
		utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
		x /= 10
		if x == 0 {
			break
		}
	}
	return string(buf[i:])
}
<commit_msg>[dev.typeparams] go/types: adjust printing of embedded struct fields (fixes x/tools/cmd/guru tests)<commit_after>// Copyright 2013 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.

// This file implements printing of types.

package types

import (
	"bytes"
	"fmt"
	"unicode/utf8"
)

// A Qualifier controls how named package-level objects are printed in
// calls to TypeString, ObjectString, and SelectionString.
//
// These three formatting routines call the Qualifier for each
// package-level object O, and if the Qualifier returns a non-empty
// string p, the object is printed in the form p.O.
// If it returns an empty string, only the object name O is printed.
//
// Using a nil Qualifier is equivalent to using (*Package).Path: the
// object is qualified by the import path, e.g., "encoding/json.Marshal".
//
type Qualifier func(*Package) string

// RelativeTo returns a Qualifier that fully qualifies members of
// all packages other than pkg.
func RelativeTo(pkg *Package) Qualifier {
	if pkg == nil {
		return nil
	}
	return func(other *Package) string {
		if pkg == other {
			return "" // same package; unqualified
		}
		return other.Path()
	}
}

// If gcCompatibilityMode is set, printing of types is modified
// to match the representation of some types in the gc compiler:
//
//	- byte and rune lose their alias name and simply stand for
//	  uint8 and int32 respectively
//	- embedded interfaces get flattened (the embedding info is lost,
//	  and certain recursive interface types cannot be printed anymore)
//
// This makes it easier to compare packages computed with the type-
// checker vs packages imported from gc export data.
//
// Caution: This flag affects all uses of WriteType, globally.
// It is only provided for testing in conjunction with
// gc-generated data.
//
// This flag is exported in the x/tools/go/types package. We don't
// need it at the moment in the std repo and so we don't export it
// anymore. We should eventually try to remove it altogether.
// TODO(gri) remove this
var gcCompatibilityMode bool

// TypeString returns the string representation of typ.
// The Qualifier controls the printing of
// package-level objects, and may be nil.
func TypeString(typ Type, qf Qualifier) string {
	var buf bytes.Buffer
	WriteType(&buf, typ, qf)
	return buf.String()
}

// WriteType writes the string representation of typ to buf.
// The Qualifier controls the printing of
// package-level objects, and may be nil.
func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
	writeType(buf, typ, qf, make([]Type, 0, 8))
}

// instanceMarker is the prefix for an instantiated type
// in "non-evaluated" instance form.
const instanceMarker = '#'

func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
	// Theoretically, this is a quadratic lookup algorithm, but in
	// practice deeply nested composite types with unnamed component
	// types are uncommon. This code is likely more efficient than
	// using a map.
	for _, t := range visited {
		if t == typ {
			fmt.Fprintf(buf, "○%T", goTypeName(typ)) // cycle to typ
			return
		}
	}
	visited = append(visited, typ)

	switch t := typ.(type) {
	case nil:
		buf.WriteString("<nil>")

	case *Basic:
		if t.kind == UnsafePointer {
			buf.WriteString("unsafe.")
		}
		if gcCompatibilityMode {
			// forget the alias names
			switch t.kind {
			case Byte:
				t = Typ[Uint8]
			case Rune:
				t = Typ[Int32]
			}
		}
		buf.WriteString(t.name)

	case *Array:
		fmt.Fprintf(buf, "[%d]", t.len)
		writeType(buf, t.elem, qf, visited)

	case *Slice:
		buf.WriteString("[]")
		writeType(buf, t.elem, qf, visited)

	case *Struct:
		buf.WriteString("struct{")
		for i, f := range t.fields {
			if i > 0 {
				buf.WriteString("; ")
			}
			// For compatibility with versions < go1.16, qualify the field name
			// of embedded fields with the package name. Various tests (such as
			// in x/tools/cmd/guru) depend on this output; and x/tools packages
			// are run against earlier versions of Go.
			if n, _ := f.typ.(*Named); f.embedded && n != nil && n.obj != nil && n.obj.pkg != nil {
				writePackage(buf, n.obj.pkg, qf)
			}
			buf.WriteString(f.name)
			if f.embedded {
				// emphasize that the embedded field's name
				// doesn't match the field's type name
				if f.name != embeddedFieldName(f.typ) {
					buf.WriteString(" /* = ")
					writeType(buf, f.typ, qf, visited)
					buf.WriteString(" */")
				}
			} else {
				buf.WriteByte(' ')
				writeType(buf, f.typ, qf, visited)
			}
			if tag := t.Tag(i); tag != "" {
				fmt.Fprintf(buf, " %q", tag)
			}
		}
		buf.WriteByte('}')

	case *Pointer:
		buf.WriteByte('*')
		writeType(buf, t.base, qf, visited)

	case *Tuple:
		writeTuple(buf, t, false, qf, visited)

	case *Signature:
		buf.WriteString("func")
		writeSignature(buf, t, qf, visited)

	case *Sum:
		for i, t := range t.types {
			if i > 0 {
				buf.WriteString(", ")
			}
			writeType(buf, t, qf, visited)
		}

	case *Interface:
		// We write the source-level methods and embedded types rather
		// than the actual method set since resolved method signatures
		// may have non-printable cycles if parameters have embedded
		// interface types that (directly or indirectly) embed the
		// current interface. For instance, consider the result type
		// of m:
		//
		//     type T interface{
		//         m() interface{ T }
		//     }
		//
		buf.WriteString("interface{")
		empty := true
		if gcCompatibilityMode {
			// print flattened interface
			// (useful to compare against gc-generated interfaces)
			for i, m := range t.allMethods {
				if i > 0 {
					buf.WriteString("; ")
				}
				buf.WriteString(m.name)
				writeSignature(buf, m.typ.(*Signature), qf, visited)
				empty = false
			}
			if !empty && t.allTypes != nil {
				buf.WriteString("; ")
			}
			if t.allTypes != nil {
				buf.WriteString("type ")
				writeType(buf, t.allTypes, qf, visited)
			}
		} else {
			// print explicit interface methods and embedded types
			for i, m := range t.methods {
				if i > 0 {
					buf.WriteString("; ")
				}
				buf.WriteString(m.name)
				writeSignature(buf, m.typ.(*Signature), qf, visited)
				empty = false
			}
			if !empty && t.types != nil {
				buf.WriteString("; ")
			}
			if t.types != nil {
				buf.WriteString("type ")
				writeType(buf, t.types, qf, visited)
				empty = false
			}
			if !empty && len(t.embeddeds) > 0 {
				buf.WriteString("; ")
			}
			for i, typ := range t.embeddeds {
				if i > 0 {
					buf.WriteString("; ")
				}
				writeType(buf, typ, qf, visited)
				empty = false
			}
		}
		if t.allMethods == nil || len(t.methods) > len(t.allMethods) {
			if !empty {
				buf.WriteByte(' ')
			}
			buf.WriteString("/* incomplete */")
		}
		buf.WriteByte('}')

	case *Map:
		buf.WriteString("map[")
		writeType(buf, t.key, qf, visited)
		buf.WriteByte(']')
		writeType(buf, t.elem, qf, visited)

	case *Chan:
		var s string
		var parens bool
		switch t.dir {
		case SendRecv:
			s = "chan "
			// chan (<-chan T) requires parentheses
			if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
				parens = true
			}
		case SendOnly:
			s = "chan<- "
		case RecvOnly:
			s = "<-chan "
		default:
			panic("unreachable")
		}
		buf.WriteString(s)
		if parens {
			buf.WriteByte('(')
		}
		writeType(buf, t.elem, qf, visited)
		if parens {
			buf.WriteByte(')')
		}

	case *Named:
		writeTypeName(buf, t.obj, qf)
		if t.targs != nil {
			// instantiated type
			buf.WriteByte('[')
			writeTypeList(buf, t.targs, qf, visited)
			buf.WriteByte(']')
		} else if t.tparams != nil {
			// parameterized type
			writeTParamList(buf, t.tparams, qf, visited)
		}

	case *TypeParam:
		s := "?"
		if t.obj != nil {
			s = t.obj.name
		}
		buf.WriteString(s + subscript(t.id))

	case *instance:
		buf.WriteByte(instanceMarker) // indicate "non-evaluated" syntactic instance
		writeTypeName(buf, t.base.obj, qf)
		buf.WriteByte('[')
		writeTypeList(buf, t.targs, qf, visited)
		buf.WriteByte(']')

	case *bottom:
		buf.WriteString("⊥")

	case *top:
		buf.WriteString("⊤")

	default:
		// For externally defined implementations of Type.
		buf.WriteString(t.String())
	}
}

func writeTypeList(buf *bytes.Buffer, list []Type, qf Qualifier, visited []Type) {
	for i, typ := range list {
		if i > 0 {
			buf.WriteString(", ")
		}
		writeType(buf, typ, qf, visited)
	}
}

func writeTParamList(buf *bytes.Buffer, list []*TypeName, qf Qualifier, visited []Type) {
	// TODO(rFindley) compare this with the corresponding implementation in types2
	buf.WriteString("[")
	var prev Type
	for i, p := range list {
		// TODO(rFindley) support 'any' sugar here.
		var b Type = &emptyInterface
		if t, _ := p.typ.(*TypeParam); t != nil && t.bound != nil {
			b = t.bound
		}
		if i > 0 {
			if b != prev {
				// type bound changed - write previous one before advancing
				buf.WriteByte(' ')
				writeType(buf, prev, qf, visited)
			}
			buf.WriteString(", ")
		}
		prev = b

		if t, _ := p.typ.(*TypeParam); t != nil {
			writeType(buf, t, qf, visited)
		} else {
			buf.WriteString(p.name)
		}
	}
	if prev != nil {
		buf.WriteByte(' ')
		writeType(buf, prev, qf, visited)
	}
	buf.WriteByte(']')
}

func writeTypeName(buf *bytes.Buffer, obj *TypeName, qf Qualifier) {
	s := "<Named w/o object>"
	if obj != nil {
		if obj.pkg != nil {
			writePackage(buf, obj.pkg, qf)
		}
		// TODO(gri): function-local named types should be displayed
		// differently from named types at package level to avoid
		// ambiguity.
		s = obj.name
	}
	buf.WriteString(s)
}

func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
	buf.WriteByte('(')
	if tup != nil {
		for i, v := range tup.vars {
			if i > 0 {
				buf.WriteString(", ")
			}
			if v.name != "" {
				buf.WriteString(v.name)
				buf.WriteByte(' ')
			}
			typ := v.typ
			if variadic && i == len(tup.vars)-1 {
				if s, ok := typ.(*Slice); ok {
					buf.WriteString("...")
					typ = s.elem
				} else {
					// special case:
					// append(s, "foo"...) leads to signature func([]byte, string...)
					if t := asBasic(typ); t == nil || t.kind != String {
						panic("internal error: string type expected")
					}
					writeType(buf, typ, qf, visited)
					buf.WriteString("...")
					continue
				}
			}
			writeType(buf, typ, qf, visited)
		}
	}
	buf.WriteByte(')')
}

// WriteSignature writes the representation of the signature sig to buf,
// without a leading "func" keyword.
// The Qualifier controls the printing of
// package-level objects, and may be nil.
func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
	writeSignature(buf, sig, qf, make([]Type, 0, 8))
}

func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
	if sig.tparams != nil {
		writeTParamList(buf, sig.tparams, qf, visited)
	}

	writeTuple(buf, sig.params, sig.variadic, qf, visited)

	n := sig.results.Len()
	if n == 0 {
		// no result
		return
	}

	buf.WriteByte(' ')
	if n == 1 && sig.results.vars[0].name == "" {
		// single unnamed result
		writeType(buf, sig.results.vars[0].typ, qf, visited)
		return
	}

	// multiple or named result(s)
	writeTuple(buf, sig.results, false, qf, visited)
}

// embeddedFieldName returns an embedded field's name given its type.
// The result is "" if the type doesn't have an embedded field name.
func embeddedFieldName(typ Type) string {
	switch t := typ.(type) {
	case *Basic:
		return t.name
	case *Named:
		return t.obj.name
	case *Pointer:
		// *T is ok, but **T is not
		if _, ok := t.base.(*Pointer); !ok {
			return embeddedFieldName(t.base)
		}
	case *instance:
		return t.base.obj.name
	}
	return "" // not a (pointer to) a defined type
}

// subscript returns the decimal (utf8) representation of x using subscript digits.
func subscript(x uint64) string {
	const w = len("₀") // all digits 0...9 have the same utf8 width
	var buf [32 * w]byte
	i := len(buf)
	for {
		i -= w
		utf8.EncodeRune(buf[i:], '₀'+rune(x%10)) // '₀' == U+2080
		x /= 10
		if x == 0 {
			break
		}
	}
	return string(buf[i:])
}
<|endoftext|>


<commit_before>// @author       sigu-399
// @description  An implementation of JSON Schema, draft v4 - Go language
// @created      26-02-2013

package gojsonschema

import (
	"errors"
	"fmt"
	"reflect"
)

const (
	JSON_SCHEMA_MUST_BE_OBJECT = `Schema root must be an object`
	MUST_BE_STRING             = `'%s' must be a string`
	IS_REQUIRED                = `'%s' is required`
	ENUM_VALUE_NOT_ALLOWED     = `%s '%s' is not allowed`
)

const (
	KEY_SCHEMA      = `$schema`
	KEY_ID          = `id`
	KEY_TITLE       = `title`
	KEY_DESCRIPTION = `description`
	KEY_TYPE        = `type`
)

func NewJsonSchema(document interface{}) (JsonSchema, error) {

	var s JsonSchema
	err := s.parse(document)
	return s, err

}

type JsonSchema struct {
	schemaKeyword      string
	idKeyword          string
	titleKeyword       string
	descriptionKeyword string
	typeKeyword        string

	document interface{}
}

func (s *JsonSchema) parse(document interface{}) error {

	s.document = document

	if !interfaceOfKind(s.document, reflect.Map) {
		return errors.New(JSON_SCHEMA_MUST_BE_OBJECT)
	}

	schemaMap := s.document.(map[string]interface{})

	// $schema
	if !mapValueExists(schemaMap, KEY_SCHEMA) {
		return errors.New(fmt.Sprintf(IS_REQUIRED, KEY_SCHEMA))
	}

	if !interfaceOfKind(schemaMap[KEY_SCHEMA], reflect.String) {
		return errors.New(fmt.Sprintf(MUST_BE_STRING, KEY_SCHEMA))
	}

	s.schemaKeyword = schemaMap[KEY_SCHEMA].(string)

	if !isStringInList(SUPPORTED_SCHEMA_KEYWORDS, s.schemaKeyword) {
		return errors.New(fmt.Sprintf(ENUM_VALUE_NOT_ALLOWED, KEY_SCHEMA, s.schemaKeyword))
	}

	// type
	if !mapValueExists(schemaMap, KEY_TYPE) {
		return errors.New(fmt.Sprintf(IS_REQUIRED, KEY_TYPE))
	}

	if !interfaceOfKind(schemaMap[KEY_TYPE], reflect.String) {
		return errors.New(fmt.Sprintf(MUST_BE_STRING, KEY_TYPE))
	}

	s.typeKeyword = schemaMap[KEY_TYPE].(string)

	if !isStringInList(SUPPORTED_TYPE_KEYWORDS, s.typeKeyword) {
		return errors.New(fmt.Sprintf(ENUM_VALUE_NOT_ALLOWED, KEY_TYPE, s.typeKeyword))
	}

	// id

	if mapValueExists(schemaMap, KEY_ID) {
		if !interfaceOfKind(schemaMap[KEY_ID], reflect.String) {
			return errors.New(fmt.Sprintf(MUST_BE_STRING, KEY_ID))
		}
		s.idKeyword = schemaMap[KEY_ID].(string)
	}

	// title

	if mapValueExists(schemaMap, KEY_TITLE) {
		if !interfaceOfKind(schemaMap[KEY_TITLE], reflect.String) {
			return errors.New(fmt.Sprintf(MUST_BE_STRING, KEY_TITLE))
		}
		s.titleKeyword = schemaMap[KEY_TITLE].(string)
	}

	// description

	if mapValueExists(schemaMap, KEY_DESCRIPTION) {
		if !interfaceOfKind(schemaMap[KEY_DESCRIPTION], reflect.String) {
			return errors.New(fmt.Sprintf(MUST_BE_STRING, KEY_DESCRIPTION))
		}
		s.descriptionKeyword = schemaMap[KEY_DESCRIPTION].(string)
	}

	return nil
}

// Schema validation funcs

var SUPPORTED_SCHEMA_KEYWORDS []string
var SUPPORTED_TYPE_KEYWORDS []string

func init() {
	SUPPORTED_SCHEMA_KEYWORDS = []string{
		`http://json-schema.org/schema#`,
		//		`http://json-schema.org/hyper-schema#`,
		`http://json-schema.org/draft-04/schema#`,
		//		`http://json-schema.org/draft-04/hyper-schema#`,
		//		`http://json-schema.org/draft-03/schema#`,
		//		`http://json-schema.org/draft-03/hyper-schema#`,
	}
	SUPPORTED_TYPE_KEYWORDS = []string{
		`array`,
		`boolean`,
		`integer`,
		`number`,
		`null`,
		`object`,
		`string`,
	}
}

func interfaceOfKind(node interface{}, kind reflect.Kind) bool {
	return reflect.ValueOf(node).Kind() == kind
}

func mapValueExists(m map[string]interface{}, key string) bool {
	_, ok := m[key]
	return ok
}

func isStringInList(list []string, keyword string) bool {
	for _, v := range list {
		if v == keyword {
			return true
		}
	}
	return false
}
<commit_msg>redefined data structure<commit_after>// @author       sigu-399
// @description  An implementation of JSON Schema, draft v4 - Go language
// @created      26-02-2013

package gojsonschema

import (
	"errors"
	"fmt"
	"reflect"
)

const (
	JSON_SCHEMA_MUST_BE_OBJECT = `Schema root must be an object`
	MUST_BE_STRING             = `'%s' must be a string`
	IS_REQUIRED                = `'%s' is required`
	ENUM_VALUE_NOT_ALLOWED     = `%s '%s' is not allowed`
)

const (
	KEY_SCHEMA      = `$schema`
	KEY_ID          = `id`
	KEY_TITLE       = `title`
	KEY_DESCRIPTION = `description`
	KEY_TYPE        = `type`
)

func NewJsonSchemaDocument(node interface{}) (JsonSchemaDocument, error) {

	var d JsonSchemaDocument
	err := d.parse(node)
	return d, err

}

type JsonSchemaDocument struct {
	schemaKeyword string
	rootSchema    JsonSchema
	node          interface{}
}

type JsonSchema struct {
	idKeyword          string
	titleKeyword       string
	descriptionKeyword string
	typeKeyword        string
	node               interface{}
}

func (d *JsonSchemaDocument) parse(node interface{}) error {

	if !interfaceOfKind(node, reflect.Map) {
		return errors.New(JSON_SCHEMA_MUST_BE_OBJECT)
	}

	schemaMap := node.(map[string]interface{})
	d.node = schemaMap

	// $schema
	if !mapValueExists(schemaMap, KEY_SCHEMA) {
		return errors.New(fmt.Sprintf(IS_REQUIRED, KEY_SCHEMA))
	}

	if !interfaceOfKind(schemaMap[KEY_SCHEMA], reflect.String) {
		return errors.New(fmt.Sprintf(MUST_BE_STRING, KEY_SCHEMA))
	}

	d.schemaKeyword = schemaMap[KEY_SCHEMA].(string)

	if !isStringInList(SUPPORTED_SCHEMA_KEYWORDS, d.schemaKeyword) {
		return errors.New(fmt.Sprintf(ENUM_VALUE_NOT_ALLOWED, KEY_SCHEMA, d.schemaKeyword))
	}

	return d.rootSchema.parse(d.node)

}

func (s *JsonSchema) parse(node interface{}) error {

	if !interfaceOfKind(node, reflect.Map) {
		return errors.New(JSON_SCHEMA_MUST_BE_OBJECT)
	}

	schemaMap := node.(map[string]interface{})
	s.node = schemaMap

	// type
	if !mapValueExists(schemaMap, KEY_TYPE) {
		return errors.New(fmt.Sprintf(IS_REQUIRED, KEY_TYPE))
	}

	if !interfaceOfKind(schemaMap[KEY_TYPE], reflect.String) {
		return errors.New(fmt.Sprintf(MUST_BE_STRING, KEY_TYPE))
	}

	s.typeKeyword = schemaMap[KEY_TYPE].(string)

	if !isStringInList(SUPPORTED_TYPE_KEYWORDS, s.typeKeyword) {
		return errors.New(fmt.Sprintf(ENUM_VALUE_NOT_ALLOWED, KEY_TYPE, s.typeKeyword))
	}

	// id

	if mapValueExists(schemaMap, KEY_ID) {
		if !interfaceOfKind(schemaMap[KEY_ID], reflect.String) {
			return errors.New(fmt.Sprintf(MUST_BE_STRING, KEY_ID))
		}
		s.idKeyword = schemaMap[KEY_ID].(string)
	}

	// title

	if mapValueExists(schemaMap, KEY_TITLE) {
		if !interfaceOfKind(schemaMap[KEY_TITLE], reflect.String) {
			return errors.New(fmt.Sprintf(MUST_BE_STRING, KEY_TITLE))
		}
		s.titleKeyword = schemaMap[KEY_TITLE].(string)
	}

	// description

	if mapValueExists(schemaMap, KEY_DESCRIPTION) {
		if !interfaceOfKind(schemaMap[KEY_DESCRIPTION], reflect.String) {
			return errors.New(fmt.Sprintf(MUST_BE_STRING, KEY_DESCRIPTION))
		}
		s.descriptionKeyword = schemaMap[KEY_DESCRIPTION].(string)
	}

	return nil
}

// Schema validation funcs

var SUPPORTED_SCHEMA_KEYWORDS []string
var SUPPORTED_TYPE_KEYWORDS []string

func init() {
	SUPPORTED_SCHEMA_KEYWORDS = []string{
		`http://json-schema.org/schema#`,
		//		`http://json-schema.org/hyper-schema#`,
		`http://json-schema.org/draft-04/schema#`,
		//		`http://json-schema.org/draft-04/hyper-schema#`,
		//		`http://json-schema.org/draft-03/schema#`,
		//		`http://json-schema.org/draft-03/hyper-schema#`,
	}
	SUPPORTED_TYPE_KEYWORDS = []string{
		`array`,
		`boolean`,
		`integer`,
		`number`,
		`null`,
		`object`,
		`string`,
	}
}

func interfaceOfKind(node interface{}, kind reflect.Kind) bool {
	return reflect.ValueOf(node).Kind() == kind
}

func mapValueExists(m map[string]interface{}, key string) bool {
	_, ok := m[key]
	return ok
}

func isStringInList(list []string, keyword string) bool {
	for _, v := range list {
		if v == keyword {
			return true
		}
	}
	return false
}
<|endoftext|>


<commit_before>package avl

import "fmt"

func max(a, b int) int {
	if a >= b {
		return a
	}
	return b
}

type AVLNode1 struct {
	value         int
	leftChild     *AVLNode1
	rightChild    *AVLNode1
	balanceFactor int
}

//   X          Z
//  / \        / \
// T1  Z  =>  X  T4
//    / \    / \
//  T23 T4  T1 T23
func (x *AVLNode1) leftRotate(ptrX **AVLNode1) {
	z := x.rightChild
	x.rightChild = z.leftChild // T23
	z.leftChild = x
	if z.balanceFactor == 0 {
		// Example:
		// T1.height() = 4
		// Z.height() = 6
		// T23.height() = 5
		// T4.height() = 5
		x.balanceFactor = 1
		z.balanceFactor = -1
	} else if z.balanceFactor == 1 {
		// Case: z.balanceFactor == 1
		// Example:
		// T1.height() = 4
		// Z.height() = 6
		// T23.height() = 4
		// T4.height() = 5
		x.balanceFactor = 0
		z.balanceFactor = 0
	} else {
		panic(fmt.Errorf("z.balanceFactor == %d", z.balanceFactor))
	}
	*ptrX = z
}

//     Z          X
//    / \        / \
//   X  T4  =>  T1  Z
//  / \            / \
// T1 T23        T23 T4
func (z *AVLNode1) rightRotate(ptrZ **AVLNode1) {
	x := z.leftChild
	z.leftChild = x.rightChild // T23
	x.rightChild = z
	if x.balanceFactor == 0 {
		// Example:
		// X.height() = 6
		// T1.height() = 5
		// T23.height() = 5
		// T4.height() = 4
		z.balanceFactor = -1
		x.balanceFactor = 1
	} else if x.balanceFactor == -1 {
		// Case: x.balanceFactor == -1
		// Example:
		// X.height() = 6
		// T1.height() = 5
		// T23.height() = 4
		// T4.height() = 4
		z.balanceFactor = 0
		x.balanceFactor = 0
	} else {
		panic(fmt.Errorf("x.balanceFactor == %d", x.balanceFactor))
	}
	*ptrZ = x
}

func (n *AVLNode1) height() int {
	if n == nil {
		return -1
	}
	leftHeight := n.leftChild.height()
	rightHeight := n.rightChild.height()
	return max(leftHeight, rightHeight) + 1
}

func (n *AVLNode1) Contains(v int) bool {
	if n == nil {
		return false
	}
	if v < n.value {
		return n.leftChild.Contains(v)
	}
	if v > n.value {
		return n.rightChild.Contains(v)
	}
	return true
}

func (n *AVLNode1) Add(v int, ptrN **AVLNode1) bool {
	if n == nil {
		*ptrN = &AVLNode1{value: v}
		return true
	}
	if v < n.value {
		if n.leftChild.Add(v, &n.leftChild) {
			n.balanceFactor--
			if n.balanceFactor > 1 {
				// Rotation
			}
		}
	}
	if v > n.value {
		if n.rightChild.Add(v, &n.rightChild) {
			n.balanceFactor++
			if n.balanceFactor < -1 {
				// Rotation
			}
		}
	}
	// v is already in the tree
	return false
}

type AVLTree1 struct {
	root *AVLNode1
}

func (t *AVLTree1) Contains(v int) bool {
	return t.root.Contains(v)
}

func (t *AVLTree1) Add(v int) {
	t.root.Add(v, &t.root)
}

func (t *AVLTree1) AddAll(vs []int) {
	for v := range vs {
		t.Add(v)
	}
}
<commit_msg>Deleted unused file<commit_after><|endoftext|>


<commit_before>package compile

import (
	"fmt"
	"strconv"

	"github.com/raviqqe/tisp/src/lib/core"
	"github.com/raviqqe/tisp/src/lib/std"
)

func prelude() environment {
	e := newEnvironment(func(name string) (*core.Thunk, error) {
		if n, err := strconv.ParseInt(name, 0, 64); err == nil && name[0] == '0' {
			return core.NewNumber(float64(n)), nil
		}

		if n, err := strconv.ParseFloat(name, 64); err == nil {
			return core.NewNumber(n), nil
		}

		if s, err := strconv.Unquote(name); err == nil {
			return core.NewString(s), nil
		}

		return nil, fmt.Errorf("the name, %s not found", name)
	})

	for _, nv := range []struct {
		name  string
		value *core.Thunk
	}{
		{"true", core.True},
		{"false", core.False},
		{"if", core.If},

		{"partial", core.Partial},

		{"first", core.First},
		{"rest", core.Rest},
		{"prepend", core.Prepend},

		{"nil", core.Nil},

		{"+", core.Add},
		{"-", core.Sub},
		{"*", core.Mul},
		{"/", core.Div},
		{"mod", core.Mod},
		{"pow", core.Pow},

		{"=", core.Equal},
		{"toList", core.ToList},
		{"toStr", core.ToString},

		{"list", std.List},
		{"$list", std.List},
		{"dict", std.Dictionary},
		{"$dict", std.Dictionary},

		{"y", std.Y},
		{"ys", std.Ys},

		{"seq", std.Seq},

		{"write", std.Write},
	} {
		e.set(nv.name, nv.value)
	}

	return e
}
<commit_msg>Use Python like power operator<commit_after>package compile

import (
	"fmt"
	"strconv"

	"github.com/raviqqe/tisp/src/lib/core"
	"github.com/raviqqe/tisp/src/lib/std"
)

func prelude() environment {
	e := newEnvironment(func(name string) (*core.Thunk, error) {
		if n, err := strconv.ParseInt(name, 0, 64); err == nil && name[0] == '0' {
			return core.NewNumber(float64(n)), nil
		}

		if n, err := strconv.ParseFloat(name, 64); err == nil {
			return core.NewNumber(n), nil
		}

		if s, err := strconv.Unquote(name); err == nil {
			return core.NewString(s), nil
		}

		return nil, fmt.Errorf("the name, %s not found", name)
	})

	for _, nv := range []struct {
		name  string
		value *core.Thunk
	}{
		{"true", core.True},
		{"false", core.False},
		{"if", core.If},

		{"partial", core.Partial},

		{"first", core.First},
		{"rest", core.Rest},
		{"prepend", core.Prepend},

		{"nil", core.Nil},

		{"+", core.Add},
		{"-", core.Sub},
		{"*", core.Mul},
		{"/", core.Div},
		{"mod", core.Mod},
		{"**", core.Pow},

		{"=", core.Equal},
		{"toList", core.ToList},
		{"toStr", core.ToString},

		{"list", std.List},
		{"$list", std.List},
		{"dict", std.Dictionary},
		{"$dict", std.Dictionary},

		{"y", std.Y},
		{"ys", std.Ys},

		{"seq", std.Seq},

		{"write", std.Write},
	} {
		e.set(nv.name, nv.value)
	}

	return e
}
<|endoftext|>


<commit_before>package core

type collection interface {
	callable

	include(Value) Value
	index(Value) Value
	insert(...*Thunk) Value
	merge(...*Thunk) Value
	delete(Value) Value
	toList() Value
	size() Value
}

// Include returns true if a collection includes an element, or false otherwise.
var Include = NewStrictFunction(
	NewSignature(
		[]string{"collection", "elem"}, nil, "",
		nil, nil, "",
	),
	func(ts ...*Thunk) Value {
		v := ts[0].Eval()
		c, ok := v.(collection)

		if !ok {
			return TypeError(v, "collection")
		}

		v = ts[1].Eval()
		if err, ok := v.(ErrorType); ok {
			return err
		}

		return c.include(v)
	})

// Index extracts an element corresponding with a key.
var Index = NewStrictFunction(
	NewSignature(
		[]string{"collection", "key"}, nil, "",
		nil, nil, "",
	),
	func(ts ...*Thunk) Value {
		v := ts[0].Eval()
		i, ok := v.(collection)

		if !ok {
			return TypeError(v, "collection")
		}

		return i.index(ts[1].Eval())
	})

// Insert inserts an element into a collection.
var Insert = NewLazyFunction(
	NewSignature(
		[]string{"collection"}, nil, "values",
		nil, nil, "",
	),
	func(ts ...*Thunk) (result Value) {
		v := ts[0].Eval()
		c, ok := v.(collection)

		if !ok {
			return NotCollectionError(v)
		}

		v = ts[1].Eval()
		l, ok := v.(ListType)

		if !ok {
			return NotListError(v)
		}

		ts, err := l.ToThunks()

		if err != nil {
			return err
		}

		return c.insert(ts...)
	})

// Merge merges 2 collections.
var Merge = NewLazyFunction(
	NewSignature(
		[]string{"x"}, nil, "ys",
		nil, nil, "",
	),
	func(ts ...*Thunk) Value {
		v := ts[0].Eval()
		m, ok := v.(collection)

		if !ok {
			return TypeError(v, "collection")
		}

		v = ts[1].Eval()
		l, ok := v.(ListType)

		if !ok {
			return NotListError(v)
		}

		ts, err := l.ToThunks()

		if err != nil {
			return err
		}

		if len(ts) == 0 {
			return m
		}

		return m.merge(ts...)
	})

// Delete deletes an element corresponding with a key.
var Delete = NewStrictFunction(
	NewSignature(
		[]string{"collection", "elem"}, nil, "",
		nil, nil, "",
	),
	func(ts ...*Thunk) Value {
		v := ts[0].Eval()
		d, ok := v.(collection)

		if !ok {
			return TypeError(v, "collection")
		}

		return d.delete(ts[1].Eval())
	})

// Size returns a size of a collection.
var Size = NewLazyFunction(
	NewSignature(
		[]string{"collection"}, nil, "",
		nil, nil, "",
	),
	func(ts ...*Thunk) Value {
		v := ts[0].Eval()
		c, ok := v.(collection)

		if !ok {
			return TypeError(v, "collection")
		}

		return c.size()
	})

// ToList converts a collection into a list of its elements.
var ToList = NewLazyFunction(
	NewSignature(
		[]string{"listLike"}, nil, "",
		nil, nil, "",
	),
	func(ts ...*Thunk) Value {
		v := ts[0].Eval()
		l, ok := v.(collection)

		if !ok {
			return TypeError(v, "collection")
		}

		return l.toList()
	})
<commit_msg>Fix variable name<commit_after>package core

type collection interface {
	callable

	include(Value) Value
	index(Value) Value
	insert(...*Thunk) Value
	merge(...*Thunk) Value
	delete(Value) Value
	toList() Value
	size() Value
}

// Include returns true if a collection includes an element, or false otherwise.
var Include = NewStrictFunction(
	NewSignature(
		[]string{"collection", "elem"}, nil, "",
		nil, nil, "",
	),
	func(ts ...*Thunk) Value {
		v := ts[0].Eval()
		c, ok := v.(collection)

		if !ok {
			return TypeError(v, "collection")
		}

		v = ts[1].Eval()
		if err, ok := v.(ErrorType); ok {
			return err
		}

		return c.include(v)
	})

// Index extracts an element corresponding with a key.
var Index = NewStrictFunction(
	NewSignature(
		[]string{"collection", "key"}, nil, "",
		nil, nil, "",
	),
	func(ts ...*Thunk) Value {
		v := ts[0].Eval()
		c, ok := v.(collection)

		if !ok {
			return TypeError(v, "collection")
		}

		return c.index(ts[1].Eval())
	})

// Insert inserts an element into a collection.
var Insert = NewLazyFunction(
	NewSignature(
		[]string{"collection"}, nil, "values",
		nil, nil, "",
	),
	func(ts ...*Thunk) (result Value) {
		v := ts[0].Eval()
		c, ok := v.(collection)

		if !ok {
			return NotCollectionError(v)
		}

		v = ts[1].Eval()
		l, ok := v.(ListType)

		if !ok {
			return NotListError(v)
		}

		ts, err := l.ToThunks()

		if err != nil {
			return err
		}

		return c.insert(ts...)
	})

// Merge merges 2 collections.
var Merge = NewLazyFunction(
	NewSignature(
		[]string{"x"}, nil, "ys",
		nil, nil, "",
	),
	func(ts ...*Thunk) Value {
		v := ts[0].Eval()
		m, ok := v.(collection)

		if !ok {
			return TypeError(v, "collection")
		}

		v = ts[1].Eval()
		l, ok := v.(ListType)

		if !ok {
			return NotListError(v)
		}

		ts, err := l.ToThunks()

		if err != nil {
			return err
		}

		if len(ts) == 0 {
			return m
		}

		return m.merge(ts...)
	})

// Delete deletes an element corresponding with a key.
var Delete = NewStrictFunction(
	NewSignature(
		[]string{"collection", "elem"}, nil, "",
		nil, nil, "",
	),
	func(ts ...*Thunk) Value {
		v := ts[0].Eval()
		d, ok := v.(collection)

		if !ok {
			return TypeError(v, "collection")
		}

		return d.delete(ts[1].Eval())
	})

// Size returns a size of a collection.
var Size = NewLazyFunction(
	NewSignature(
		[]string{"collection"}, nil, "",
		nil, nil, "",
	),
	func(ts ...*Thunk) Value {
		v := ts[0].Eval()
		c, ok := v.(collection)

		if !ok {
			return TypeError(v, "collection")
		}

		return c.size()
	})

// ToList converts a collection into a list of its elements.
var ToList = NewLazyFunction(
	NewSignature(
		[]string{"listLike"}, nil, "",
		nil, nil, "",
	),
	func(ts ...*Thunk) Value {
		v := ts[0].Eval()
		l, ok := v.(collection)

		if !ok {
			return TypeError(v, "collection")
		}

		return l.toList()
	})
<|endoftext|>


<commit_before>// Copyright 2022 Google LLC
//
// 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 base_leader_election_test

import (
	"context"
	"testing"
	"time"

	"github.com/openconfig/featureprofiles/internal/attrs"
	"github.com/openconfig/featureprofiles/internal/deviations"
	"github.com/openconfig/featureprofiles/internal/fptest"
	"github.com/openconfig/featureprofiles/internal/gribi"
	"github.com/openconfig/gribigo/fluent"
	"github.com/openconfig/ondatra"
	"github.com/openconfig/ondatra/telemetry"
	"github.com/openconfig/ygot/ygot"
)

func TestMain(m *testing.M) {
	fptest.RunTests(m)
}

// Settings for configuring the baseline testbed with the test
// topology.
//
// The testbed consists of ate:port1 -> dut:port1,
// dut:port2 -> ate:port2 and dut:port3 -> ate:port3.
//
//   * ate:port1 -> dut:port1 subnet 192.0.2.0/30
//   * ate:port2 -> dut:port2 subnet 192.0.2.4/30
//   * ate:port3 -> dut:port3 subnet 192.0.2.8/30
//
//   * Destination network: 198.51.100.0/24

const (
	ipv4PrefixLen = 30
	instance      = "default"
	ateDstNetCIDR = "198.51.100.0/24"
	nhIndex       = 1
	nhgIndex      = 42
)

var (
	dutPort1 = attrs.Attributes{
		Desc:    "dutPort1",
		IPv4:    "192.0.2.1",
		IPv4Len: ipv4PrefixLen,
	}

	atePort1 = attrs.Attributes{
		Name:    "atePort1",
		IPv4:    "192.0.2.2",
		IPv4Len: ipv4PrefixLen,
	}

	dutPort2 = attrs.Attributes{
		Desc:    "dutPort2",
		IPv4:    "192.0.2.5",
		IPv4Len: ipv4PrefixLen,
	}

	atePort2 = attrs.Attributes{
		Name:    "atePort2",
		IPv4:    "192.0.2.6",
		IPv4Len: ipv4PrefixLen,
	}

	dutPort3 = attrs.Attributes{
		Desc:    "dutPort3",
		IPv4:    "192.0.2.9",
		IPv4Len: ipv4PrefixLen,
	}

	atePort3 = attrs.Attributes{
		Name:    "atePort3",
		IPv4:    "192.0.2.10",
		IPv4Len: ipv4PrefixLen,
	}
)

// configInterfaceDUT configures the interface with the Addrs.
func configInterfaceDUT(i *telemetry.Interface, a *attrs.Attributes) *telemetry.Interface {
	i.Description = ygot.String(a.Desc)
	i.Type = telemetry.IETFInterfaces_InterfaceType_ethernetCsmacd
	if *deviations.InterfaceEnabled {
		i.Enabled = ygot.Bool(true)
	}

	s := i.GetOrCreateSubinterface(0)
	s4 := s.GetOrCreateIpv4()
	if *deviations.InterfaceEnabled {
		s4.Enabled = ygot.Bool(true)
	}
	s4a := s4.GetOrCreateAddress(a.IPv4)
	s4a.PrefixLength = ygot.Uint8(ipv4PrefixLen)

	return i
}

// configureDUT configures port1, port2 and port3 on the DUT.
func configureDUT(t *testing.T, dut *ondatra.DUTDevice) {
	d := dut.Config()

	p1 := dut.Port(t, "port1")
	i1 := &telemetry.Interface{Name: ygot.String(p1.Name())}
	d.Interface(p1.Name()).Replace(t, configInterfaceDUT(i1, &dutPort1))

	p2 := dut.Port(t, "port2")
	i2 := &telemetry.Interface{Name: ygot.String(p2.Name())}
	d.Interface(p2.Name()).Replace(t, configInterfaceDUT(i2, &dutPort2))

	p3 := dut.Port(t, "port3")
	i3 := &telemetry.Interface{Name: ygot.String(p3.Name())}
	d.Interface(p3.Name()).Replace(t, configInterfaceDUT(i3, &dutPort3))
}

// configureATE configures port1, port2 and port3 on the ATE.
func configureATE(t *testing.T, ate *ondatra.ATEDevice) *ondatra.ATETopology {
	top := ate.Topology().New()

	p1 := ate.Port(t, "port1")
	i1 := top.AddInterface(atePort1.Name).WithPort(p1)
	i1.IPv4().
		WithAddress(atePort1.IPv4CIDR()).
		WithDefaultGateway(dutPort1.IPv4)

	p2 := ate.Port(t, "port2")
	i2 := top.AddInterface(atePort2.Name).WithPort(p2)
	i2.IPv4().
		WithAddress(atePort2.IPv4CIDR()).
		WithDefaultGateway(dutPort2.IPv4)

	p3 := ate.Port(t, "port3")
	i3 := top.AddInterface(atePort3.Name).WithPort(p3)
	i3.IPv4().
		WithAddress(atePort3.IPv4CIDR()).
		WithDefaultGateway(dutPort3.IPv4)

	return top
}

// testTraffic generates traffic flow from source network to
// destination network via srcEndPoint to dstEndPoint and checks for
// packet loss.
func testTraffic(t *testing.T, ate *ondatra.ATEDevice, top *ondatra.ATETopology, srcEndPoint, dstEndPoint *ondatra.Interface) {
	ethHeader := ondatra.NewEthernetHeader()
	ipv4Header := ondatra.NewIPv4Header()
	ipv4Header.DstAddressRange().
		WithMin("198.51.100.0").
		WithMax("198.51.100.254").
		WithCount(250)

	flow := ate.Traffic().NewFlow("Flow").
		WithSrcEndpoints(srcEndPoint).
		WithDstEndpoints(dstEndPoint).
		WithHeaders(ethHeader, ipv4Header)

	ate.Traffic().Start(t, flow)
	time.Sleep(15 * time.Second)
	ate.Traffic().Stop(t)

	time.Sleep(time.Minute)

	flowPath := ate.Telemetry().Flow(flow.Name())
	if got := flowPath.LossPct().Get(t); got > 0 {
		t.Errorf("LossPct for flow %s got %g, want 0", flow.Name(), got)
	}
}

// testArgs holds the objects needed by a test case.
type testArgs struct {
	ctx     context.Context
	clientA *gribi.Client
	clientB *gribi.Client
	dut     *ondatra.DUTDevice
	ate     *ondatra.ATEDevice
	top     *ondatra.ATETopology
}

// testIPv4LeaderActiveChange first configures an IPV4 Entry through clientB
// and ensures that the entry is active by checking AFT Telemetry and traffic.
// It then configures an IPv4 entry through clientA without updating the election
// and ensures that the installation fails. Finally, it updated the ClientA election
// id to 12, configures an IPV4 through clinetA and ensures that the entry is active
// by checking AFT Telemetry and traffic.
func testIPv4LeaderActiveChange(ctx context.Context, t *testing.T, args *testArgs) {
	// Add an IPv4Entry for 198.51.100.0/24 pointing to ATE port-3 via gRIBI-B,
	// ensure that the entry is active through AFT telemetry and traffic.
	t.Logf("an IPv4Entry for %s pointing to ATE port-3 via gRIBI-B", ateDstNetCIDR)
	args.clientB.AddNH(t, nhIndex, atePort3.IPv4, instance, fluent.InstalledInRIB)
	args.clientB.AddNHG(t, nhgIndex, map[uint64]uint64{nhIndex: 1}, instance, fluent.InstalledInRIB)
	args.clientB.AddIPv4(t, ateDstNetCIDR, nhgIndex, instance, "", fluent.InstalledInRIB)

	// Verify the entry for 198.51.100.0/24 is active through AFT Telemetry.
	ipv4Path := args.dut.Telemetry().NetworkInstance(instance).Afts().Ipv4Entry(ateDstNetCIDR)
	if got, want := ipv4Path.Prefix().Get(t), ateDstNetCIDR; got != want {
		t.Errorf("ipv4-entry/state/prefix got %s, want %s", got, want)
	}

	// Verify the entry for 198.51.100.0/24 is active through Traffic.
	srcEndPoint := args.top.Interfaces()[atePort1.Name]
	dstEndPoint := args.top.Interfaces()[atePort3.Name]
	testTraffic(t, args.ate, args.top, srcEndPoint, dstEndPoint)

	// Add an IPv4Entry for 198.51.100.0/24 pointing to ATE port-2 via gRIBI-A,
	// ensure that the entry is ignored by the DUT.
	t.Logf("Adding an IPv4Entry for %s pointing to ATE port-2 via gRIBI-A", ateDstNetCIDR)
	args.clientA.AddNH(t, nhIndex, atePort3.IPv4, instance, fluent.ProgrammingFailed)
	args.clientA.AddNHG(t, nhgIndex, map[uint64]uint64{nhIndex: 1}, instance, fluent.ProgrammingFailed)
	args.clientA.AddIPv4(t, ateDstNetCIDR, nhgIndex, instance, "", fluent.ProgrammingFailed)

	// Send a ModifyRequest from gRIBI-A specifying election_id 12,
	// followed by a ModifyRequest updating 198.51.100.0/24 pointing to ATE port-2,
	// ensure that routing is updated to receive packets for 198.51.100.0/24 at ATE port-2.
	args.clientA.UpdateElectionID(t, 12, 0)
	t.Logf("Adding an IPv4Entry for %s pointing to ATE port-2 via client gRIBI-A", ateDstNetCIDR)
	args.clientA.AddNH(t, nhIndex, atePort2.IPv4, instance, fluent.InstalledInRIB)
	args.clientA.AddNHG(t, nhgIndex, map[uint64]uint64{nhIndex: 1}, instance, fluent.InstalledInRIB)
	args.clientA.AddIPv4(t, ateDstNetCIDR, nhgIndex, instance, "", fluent.InstalledInRIB)

	// Verify the entry for 198.51.100.0/24 is active through AFT Telemetry.
	ipv4Path = args.dut.Telemetry().NetworkInstance(instance).Afts().Ipv4Entry(ateDstNetCIDR)
	if got, want := ipv4Path.Prefix().Get(t), ateDstNetCIDR; got != want {
		t.Errorf("ipv4-entry/state/prefix got %s, want %s", got, want)
	}

	// Verify with traffic that the entry for 198.51.100.0/24 is installed through the ATE port-2.
	srcEndPoint = args.top.Interfaces()[atePort1.Name]
	dstEndPoint = args.top.Interfaces()[atePort2.Name]
	testTraffic(t, args.ate, args.top, srcEndPoint, dstEndPoint)
}

func TestElectionIDChange(t *testing.T) {
	dut := ondatra.DUT(t, "dut")
	ctx := context.Background()

	// Configure the DUT
	configureDUT(t, dut)

	// Configure the ATE
	ate := ondatra.ATE(t, "ate")
	top := configureATE(t, ate)
	top.Push(t).StartProtocols(t)

	// Configure the gRIBI client clientA
	clientA := gribi.Client{
		DUT:                  dut,
		FibACK:               false,
		Persistence:          true,
		InitialElectionIDLow: 10,
	}
	defer clientA.Close(t)
	if err := clientA.Start(t); err != nil {
		t.Fatalf("gRIBI Connection can not be established")
	}

	// Configure the gRIBI client clientB
	clientB := gribi.Client{
		DUT:                  dut,
		FibACK:               false,
		Persistence:          true,
		InitialElectionIDLow: 11,
	}
	defer clientB.Close(t)
	if err := clientB.Start(t); err != nil {
		t.Fatalf("gRIBI Connection can not be established")
	}

	args := &testArgs{
		ctx:     ctx,
		clientA: &clientA,
		clientB: &clientB,
		dut:     dut,
		ate:     ate,
		top:     top,
	}

	testIPv4LeaderActiveChange(ctx, t, args)
}
<commit_msg>fix typo in base_leader_election_test (#174)<commit_after>// Copyright 2022 Google LLC
//
// 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 base_leader_election_test

import (
	"context"
	"testing"
	"time"

	"github.com/openconfig/featureprofiles/internal/attrs"
	"github.com/openconfig/featureprofiles/internal/deviations"
	"github.com/openconfig/featureprofiles/internal/fptest"
	"github.com/openconfig/featureprofiles/internal/gribi"
	"github.com/openconfig/gribigo/fluent"
	"github.com/openconfig/ondatra"
	"github.com/openconfig/ondatra/telemetry"
	"github.com/openconfig/ygot/ygot"
)

func TestMain(m *testing.M) {
	fptest.RunTests(m)
}

// Settings for configuring the baseline testbed with the test
// topology.
//
// The testbed consists of ate:port1 -> dut:port1,
// dut:port2 -> ate:port2 and dut:port3 -> ate:port3.
//
//   * ate:port1 -> dut:port1 subnet 192.0.2.0/30
//   * ate:port2 -> dut:port2 subnet 192.0.2.4/30
//   * ate:port3 -> dut:port3 subnet 192.0.2.8/30
//
//   * Destination network: 198.51.100.0/24

const (
	ipv4PrefixLen = 30
	instance      = "default"
	ateDstNetCIDR = "198.51.100.0/24"
	nhIndex       = 1
	nhgIndex      = 42
)

var (
	dutPort1 = attrs.Attributes{
		Desc:    "dutPort1",
		IPv4:    "192.0.2.1",
		IPv4Len: ipv4PrefixLen,
	}

	atePort1 = attrs.Attributes{
		Name:    "atePort1",
		IPv4:    "192.0.2.2",
		IPv4Len: ipv4PrefixLen,
	}

	dutPort2 = attrs.Attributes{
		Desc:    "dutPort2",
		IPv4:    "192.0.2.5",
		IPv4Len: ipv4PrefixLen,
	}

	atePort2 = attrs.Attributes{
		Name:    "atePort2",
		IPv4:    "192.0.2.6",
		IPv4Len: ipv4PrefixLen,
	}

	dutPort3 = attrs.Attributes{
		Desc:    "dutPort3",
		IPv4:    "192.0.2.9",
		IPv4Len: ipv4PrefixLen,
	}

	atePort3 = attrs.Attributes{
		Name:    "atePort3",
		IPv4:    "192.0.2.10",
		IPv4Len: ipv4PrefixLen,
	}
)

// configInterfaceDUT configures the interface with the Addrs.
func configInterfaceDUT(i *telemetry.Interface, a *attrs.Attributes) *telemetry.Interface {
	i.Description = ygot.String(a.Desc)
	i.Type = telemetry.IETFInterfaces_InterfaceType_ethernetCsmacd
	if *deviations.InterfaceEnabled {
		i.Enabled = ygot.Bool(true)
	}

	s := i.GetOrCreateSubinterface(0)
	s4 := s.GetOrCreateIpv4()
	if *deviations.InterfaceEnabled {
		s4.Enabled = ygot.Bool(true)
	}
	s4a := s4.GetOrCreateAddress(a.IPv4)
	s4a.PrefixLength = ygot.Uint8(ipv4PrefixLen)

	return i
}

// configureDUT configures port1, port2 and port3 on the DUT.
func configureDUT(t *testing.T, dut *ondatra.DUTDevice) {
	d := dut.Config()

	p1 := dut.Port(t, "port1")
	i1 := &telemetry.Interface{Name: ygot.String(p1.Name())}
	d.Interface(p1.Name()).Replace(t, configInterfaceDUT(i1, &dutPort1))

	p2 := dut.Port(t, "port2")
	i2 := &telemetry.Interface{Name: ygot.String(p2.Name())}
	d.Interface(p2.Name()).Replace(t, configInterfaceDUT(i2, &dutPort2))

	p3 := dut.Port(t, "port3")
	i3 := &telemetry.Interface{Name: ygot.String(p3.Name())}
	d.Interface(p3.Name()).Replace(t, configInterfaceDUT(i3, &dutPort3))
}

// configureATE configures port1, port2 and port3 on the ATE.
func configureATE(t *testing.T, ate *ondatra.ATEDevice) *ondatra.ATETopology {
	top := ate.Topology().New()

	p1 := ate.Port(t, "port1")
	i1 := top.AddInterface(atePort1.Name).WithPort(p1)
	i1.IPv4().
		WithAddress(atePort1.IPv4CIDR()).
		WithDefaultGateway(dutPort1.IPv4)

	p2 := ate.Port(t, "port2")
	i2 := top.AddInterface(atePort2.Name).WithPort(p2)
	i2.IPv4().
		WithAddress(atePort2.IPv4CIDR()).
		WithDefaultGateway(dutPort2.IPv4)

	p3 := ate.Port(t, "port3")
	i3 := top.AddInterface(atePort3.Name).WithPort(p3)
	i3.IPv4().
		WithAddress(atePort3.IPv4CIDR()).
		WithDefaultGateway(dutPort3.IPv4)

	return top
}

// testTraffic generates traffic flow from source network to
// destination network via srcEndPoint to dstEndPoint and checks for
// packet loss.
func testTraffic(t *testing.T, ate *ondatra.ATEDevice, top *ondatra.ATETopology, srcEndPoint, dstEndPoint *ondatra.Interface) {
	ethHeader := ondatra.NewEthernetHeader()
	ipv4Header := ondatra.NewIPv4Header()
	ipv4Header.DstAddressRange().
		WithMin("198.51.100.0").
		WithMax("198.51.100.254").
		WithCount(250)

	flow := ate.Traffic().NewFlow("Flow").
		WithSrcEndpoints(srcEndPoint).
		WithDstEndpoints(dstEndPoint).
		WithHeaders(ethHeader, ipv4Header)

	ate.Traffic().Start(t, flow)
	time.Sleep(15 * time.Second)
	ate.Traffic().Stop(t)

	time.Sleep(time.Minute)

	flowPath := ate.Telemetry().Flow(flow.Name())
	if got := flowPath.LossPct().Get(t); got > 0 {
		t.Errorf("LossPct for flow %s got %g, want 0", flow.Name(), got)
	}
}

// testArgs holds the objects needed by a test case.
type testArgs struct {
	ctx     context.Context
	clientA *gribi.Client
	clientB *gribi.Client
	dut     *ondatra.DUTDevice
	ate     *ondatra.ATEDevice
	top     *ondatra.ATETopology
}

// testIPv4LeaderActiveChange first configures an IPV4 Entry through clientB
// and ensures that the entry is active by checking AFT Telemetry and traffic.
// It then configures an IPv4 entry through clientA without updating the election
// and ensures that the installation fails. Finally, it updated the ClientA election
// id to 12, configures an IPV4 through clinetA and ensures that the entry is active
// by checking AFT Telemetry and traffic.
func testIPv4LeaderActiveChange(ctx context.Context, t *testing.T, args *testArgs) {
	// Add an IPv4Entry for 198.51.100.0/24 pointing to ATE port-3 via gRIBI-B,
	// ensure that the entry is active through AFT telemetry and traffic.
	t.Logf("an IPv4Entry for %s pointing to ATE port-3 via gRIBI-B", ateDstNetCIDR)
	args.clientB.AddNH(t, nhIndex, atePort3.IPv4, instance, fluent.InstalledInRIB)
	args.clientB.AddNHG(t, nhgIndex, map[uint64]uint64{nhIndex: 1}, instance, fluent.InstalledInRIB)
	args.clientB.AddIPv4(t, ateDstNetCIDR, nhgIndex, instance, "", fluent.InstalledInRIB)

	// Verify the entry for 198.51.100.0/24 is active through AFT Telemetry.
	ipv4Path := args.dut.Telemetry().NetworkInstance(instance).Afts().Ipv4Entry(ateDstNetCIDR)
	if got, want := ipv4Path.Prefix().Get(t), ateDstNetCIDR; got != want {
		t.Errorf("ipv4-entry/state/prefix got %s, want %s", got, want)
	}

	// Verify the entry for 198.51.100.0/24 is active through Traffic.
	srcEndPoint := args.top.Interfaces()[atePort1.Name]
	dstEndPoint := args.top.Interfaces()[atePort3.Name]
	testTraffic(t, args.ate, args.top, srcEndPoint, dstEndPoint)

	// Add an IPv4Entry for 198.51.100.0/24 pointing to ATE port-2 via gRIBI-A,
	// ensure that the entry is ignored by the DUT.
	t.Logf("Adding an IPv4Entry for %s pointing to ATE port-2 via gRIBI-A", ateDstNetCIDR)
	args.clientA.AddNH(t, nhIndex, atePort2.IPv4, instance, fluent.ProgrammingFailed)
	args.clientA.AddNHG(t, nhgIndex, map[uint64]uint64{nhIndex: 1}, instance, fluent.ProgrammingFailed)
	args.clientA.AddIPv4(t, ateDstNetCIDR, nhgIndex, instance, "", fluent.ProgrammingFailed)

	// Send a ModifyRequest from gRIBI-A specifying election_id 12,
	// followed by a ModifyRequest updating 198.51.100.0/24 pointing to ATE port-2,
	// ensure that routing is updated to receive packets for 198.51.100.0/24 at ATE port-2.
	args.clientA.UpdateElectionID(t, 12, 0)
	t.Logf("Adding an IPv4Entry for %s pointing to ATE port-2 via client gRIBI-A", ateDstNetCIDR)
	args.clientA.AddNH(t, nhIndex, atePort2.IPv4, instance, fluent.InstalledInRIB)
	args.clientA.AddNHG(t, nhgIndex, map[uint64]uint64{nhIndex: 1}, instance, fluent.InstalledInRIB)
	args.clientA.AddIPv4(t, ateDstNetCIDR, nhgIndex, instance, "", fluent.InstalledInRIB)

	// Verify the entry for 198.51.100.0/24 is active through AFT Telemetry.
	ipv4Path = args.dut.Telemetry().NetworkInstance(instance).Afts().Ipv4Entry(ateDstNetCIDR)
	if got, want := ipv4Path.Prefix().Get(t), ateDstNetCIDR; got != want {
		t.Errorf("ipv4-entry/state/prefix got %s, want %s", got, want)
	}

	// Verify with traffic that the entry for 198.51.100.0/24 is installed through the ATE port-2.
	srcEndPoint = args.top.Interfaces()[atePort1.Name]
	dstEndPoint = args.top.Interfaces()[atePort2.Name]
	testTraffic(t, args.ate, args.top, srcEndPoint, dstEndPoint)
}

func TestElectionIDChange(t *testing.T) {
	dut := ondatra.DUT(t, "dut")
	ctx := context.Background()

	// Configure the DUT
	configureDUT(t, dut)

	// Configure the ATE
	ate := ondatra.ATE(t, "ate")
	top := configureATE(t, ate)
	top.Push(t).StartProtocols(t)

	// Configure the gRIBI client clientA
	clientA := gribi.Client{
		DUT:                  dut,
		FibACK:               false,
		Persistence:          true,
		InitialElectionIDLow: 10,
	}
	defer clientA.Close(t)
	if err := clientA.Start(t); err != nil {
		t.Fatalf("gRIBI Connection can not be established")
	}

	// Configure the gRIBI client clientB
	clientB := gribi.Client{
		DUT:                  dut,
		FibACK:               false,
		Persistence:          true,
		InitialElectionIDLow: 11,
	}
	defer clientB.Close(t)
	if err := clientB.Start(t); err != nil {
		t.Fatalf("gRIBI Connection can not be established")
	}

	args := &testArgs{
		ctx:     ctx,
		clientA: &clientA,
		clientB: &clientB,
		dut:     dut,
		ate:     ate,
		top:     top,
	}

	testIPv4LeaderActiveChange(ctx, t, args)
}
<|endoftext|>


<commit_before>package algoliaconnector

import (
	"errors"
	"fmt"
	"socialapi/models"
	"socialapi/request"
	"strconv"
	"sync"
	"time"

	"github.com/algolia/algoliasearch-client-go/algoliasearch"
	"github.com/koding/logging"
	"github.com/streadway/amqp"
)

const (
	IndexMessages = "messages"
	IndexTopics   = "topics"
	IndexAccounts = "accounts"

	UnretrievableAttributes = "unretrievableAttributes"
	AttributesToIndex       = "attributesToIndex"
)

var (
	ErrAlgoliaObjectIdNotFoundMsg = "ObjectID does not exist"
	ErrAlgoliaIndexNotExistMsg    = "Index messages.test does not exist"
)

type Settings struct {
	AttributesToIndex       []string
	UnretrievableAttributes []string
}

type IndexSetItem struct {
	Index    *algoliasearch.Index
	Settings *Settings
}

type IndexSet map[string]*IndexSetItem

type Controller struct {
	log             logging.Logger
	client          *algoliasearch.Client
	indexes         *IndexSet
	kodingChannelId string
}

func New(log logging.Logger, client *algoliasearch.Client, indexSuffix string) *Controller {
	// TODO later on listen channel_participant_added event and remove this koding channel fetch
	c := models.NewChannel()
	q := request.NewQuery()
	q.GroupName = "koding"
	q.Name = "public"
	q.Type = models.Channel_TYPE_GROUP

	channel, err := c.ByName(q)
	if err != nil {
		log.Error("Could not fetch koding channel: %s:", err)
	}
	var channelId string
	if channel.Id != 0 {
		channelId = strconv.FormatInt(channel.Id, 10)
	}

	controller := &Controller{
		log:    log,
		client: client,
		indexes: &IndexSet{
			IndexTopics: &IndexSetItem{
				Index: client.InitIndex(IndexTopics + indexSuffix),
				Settings: &Settings{
					// empty slice means all properties will be searchable
					AttributesToIndex: []string{},
				},
			},
			IndexAccounts: &IndexSetItem{
				Index: client.InitIndex(IndexAccounts + indexSuffix),
				Settings: &Settings{
					AttributesToIndex: []string{
						"nick",
						"email",
						"_tags",
					},
					UnretrievableAttributes: []string{"email"},
				},
			},
			IndexMessages: &IndexSetItem{
				Index: client.InitIndex(IndexMessages + indexSuffix),
				Settings: &Settings{
					AttributesToIndex: []string{},
				},
			},
		},
		kodingChannelId: channelId,
	}

	return controller
}

func (i *IndexSet) Get(name string) (*IndexSetItem, error) {
	indexItem, ok := (*i)[name]
	if !ok {
		return nil, fmt.Errorf("Unknown indexItem: '%s'", name)
	}

	return indexItem, nil
}

func (i *IndexSet) GetIndex(name string) (*algoliasearch.Index, error) {
	indexItem, ok := (*i)[name]
	if !ok {
		return nil, fmt.Errorf("Unknown indexItem: '%s'", name)
	}

	return indexItem.Index, nil
}

func (c *Controller) DefaultErrHandler(delivery amqp.Delivery, err error) bool {
	c.log.Error(err.Error())
	return false
}

func (f *Controller) Init() error {
	var wg sync.WaitGroup
	for name, index := range *(f.indexes) {
		wg.Add(1)

		go func(name string, index *IndexSetItem) {
			if err := f.makeSureStringSliceSettings(name, UnretrievableAttributes, index.Settings.UnretrievableAttributes); err != nil {
				f.log.Error("indexName: %s, settings name: %s, Err: %s", name, UnretrievableAttributes, err.Error())
			}

			if err := f.makeSureStringSliceSettings(name, AttributesToIndex, index.Settings.AttributesToIndex); err != nil {
				f.log.Error("indexName: %s, settings name: %s, Err: %s", name, AttributesToIndex, err.Error())
			}
			wg.Done()
		}(name, index)
	}

	wg.Wait()

	f.log.Info("Init done!")
	return nil
}

func (f *Controller) makeSureStringSliceSettings(indexName string, settingName string, newSettings []string) error {
	indexSet, err := f.indexes.Get(indexName)
	if err != nil {
		return err
	}

	settingsinter, err := indexSet.Index.GetSettings()
	if err != nil {
		return err
	}

	settings, ok := settingsinter.(map[string]interface{})
	if !ok {
		settings = make(map[string]interface{})
	}

	indexSettings, ok := settings[settingName]
	if !ok {
		indexSettings = make([]interface{}, 0)
	}

	indexSettingsIntSlices, ok := indexSettings.([]interface{})
	if !ok {
		indexSettingsIntSlices = make([]interface{}, 0)
	}

	isSame := true
	for _, attributeToIndex := range newSettings {
		contains := false
		for _, currentAttribute := range indexSettingsIntSlices {
			if attributeToIndex == currentAttribute.(string) {
				contains = true
			}
		}

		if !contains {
			isSame = false
			break //  exit with the first condition
		}
	}

	if len(indexSettingsIntSlices) != len(newSettings) {
		isSame = false
	}

	if !isSame {
		f.log.Info(
			"Previous (%+v) and Current (%+v) Setings of %s are not same for index %s, updating..",
			indexSettingsIntSlices,
			newSettings,
			settingName,
			indexName,
		)
		settings[settingName] = newSettings
		return f.updateIndexSetting(settings, indexSet)
	}

	return err
}

func (f *Controller) updateIndexSetting(settings map[string]interface{}, indexSet *IndexSetItem) error {
	task, err := indexSet.Index.SetSettings(settings)
	if err != nil {
		return err
	}

	done := make(chan struct{})
	go func() {
		// make sure setting is propogated
		_, err = indexSet.Index.WaitTask(task)
		close(done)
	}()

	select {
	case <-done:
		return err
	case <-time.After(time.Second * 30):
		return errors.New("couldnt update index settings in 30 second")
	}
}
<commit_msg>socialapi: fix function name<commit_after>package algoliaconnector

import (
	"errors"
	"fmt"
	"socialapi/models"
	"socialapi/request"
	"strconv"
	"sync"
	"time"

	"github.com/algolia/algoliasearch-client-go/algoliasearch"
	"github.com/koding/logging"
	"github.com/streadway/amqp"
)

const (
	IndexMessages = "messages"
	IndexTopics   = "topics"
	IndexAccounts = "accounts"

	UnretrievableAttributes = "unretrievableAttributes"
	AttributesToIndex       = "attributesToIndex"
)

var (
	ErrAlgoliaObjectIdNotFoundMsg = "ObjectID does not exist"
	ErrAlgoliaIndexNotExistMsg    = "Index messages.test does not exist"
)

type Settings struct {
	AttributesToIndex       []string
	UnretrievableAttributes []string
}

type IndexSetItem struct {
	Index    *algoliasearch.Index
	Settings *Settings
}

type IndexSet map[string]*IndexSetItem

type Controller struct {
	log             logging.Logger
	client          *algoliasearch.Client
	indexes         *IndexSet
	kodingChannelId string
}

func New(log logging.Logger, client *algoliasearch.Client, indexSuffix string) *Controller {
	// TODO later on listen channel_participant_added event and remove this koding channel fetch
	c := models.NewChannel()
	q := request.NewQuery()
	q.GroupName = "koding"
	q.Name = "public"
	q.Type = models.Channel_TYPE_GROUP

	channel, err := c.ByName(q)
	if err != nil {
		log.Error("Could not fetch koding channel: %s:", err)
	}
	var channelId string
	if channel.Id != 0 {
		channelId = strconv.FormatInt(channel.Id, 10)
	}

	controller := &Controller{
		log:    log,
		client: client,
		indexes: &IndexSet{
			IndexTopics: &IndexSetItem{
				Index: client.InitIndex(IndexTopics + indexSuffix),
				Settings: &Settings{
					// empty slice means all properties will be searchable
					AttributesToIndex: []string{},
				},
			},
			IndexAccounts: &IndexSetItem{
				Index: client.InitIndex(IndexAccounts + indexSuffix),
				Settings: &Settings{
					AttributesToIndex: []string{
						"nick",
						"email",
						"_tags",
					},
					UnretrievableAttributes: []string{"email"},
				},
			},
			IndexMessages: &IndexSetItem{
				Index: client.InitIndex(IndexMessages + indexSuffix),
				Settings: &Settings{
					AttributesToIndex: []string{},
				},
			},
		},
		kodingChannelId: channelId,
	}

	return controller
}

func (i *IndexSet) Get(name string) (*IndexSetItem, error) {
	indexItem, ok := (*i)[name]
	if !ok {
		return nil, fmt.Errorf("Unknown indexItem: '%s'", name)
	}

	return indexItem, nil
}

func (i *IndexSet) GetIndex(name string) (*algoliasearch.Index, error) {
	indexItem, ok := (*i)[name]
	if !ok {
		return nil, fmt.Errorf("Unknown indexItem: '%s'", name)
	}

	return indexItem.Index, nil
}

func (c *Controller) DefaultErrHandler(delivery amqp.Delivery, err error) bool {
	c.log.Error(err.Error())
	return false
}

func (f *Controller) Init() error {
	var wg sync.WaitGroup
	for name, index := range *(f.indexes) {
		wg.Add(1)

		go func(name string, index *IndexSetItem) {
			if err := f.makeSureStringSliceSettings(name, UnretrievableAttributes, index.Settings.UnretrievableAttributes); err != nil {
				f.log.Error("indexName: %s, settings name: %s, Err: %s", name, UnretrievableAttributes, err.Error())
			}

			if err := f.makeSureStringSliceSettings(name, AttributesToIndex, index.Settings.AttributesToIndex); err != nil {
				f.log.Error("indexName: %s, settings name: %s, Err: %s", name, AttributesToIndex, err.Error())
			}
			wg.Done()
		}(name, index)
	}

	wg.Wait()

	f.log.Info("Init done!")
	return nil
}

func (f *Controller) makeSureStringSliceSettings(indexName string, settingName string, newSettings []string) error {
	indexSet, err := f.indexes.Get(indexName)
	if err != nil {
		return err
	}

	settingsinter, err := indexSet.Index.GetSettings()
	if err != nil {
		return err
	}

	settings, ok := settingsinter.(map[string]interface{})
	if !ok {
		settings = make(map[string]interface{})
	}

	indexSettings, ok := settings[settingName]
	if !ok {
		indexSettings = make([]interface{}, 0)
	}

	indexSettingsIntSlices, ok := indexSettings.([]interface{})
	if !ok {
		indexSettingsIntSlices = make([]interface{}, 0)
	}

	isSame := true
	for _, attributeToIndex := range newSettings {
		contains := false
		for _, currentAttribute := range indexSettingsIntSlices {
			if attributeToIndex == currentAttribute.(string) {
				contains = true
			}
		}

		if !contains {
			isSame = false
			break //  exit with the first condition
		}
	}

	if len(indexSettingsIntSlices) != len(newSettings) {
		isSame = false
	}

	if !isSame {
		f.log.Info(
			"Previous (%+v) and Current (%+v) Setings of %s are not same for index %s, updating..",
			indexSettingsIntSlices,
			newSettings,
			settingName,
			indexName,
		)
		settings[settingName] = newSettings
		return f.makeSureIndexSettings(settings, indexSet)
	}

	return err
}

func (f *Controller) makeSureIndexSettings(settings map[string]interface{}, indexSet *IndexSetItem) error {
	task, err := indexSet.Index.SetSettings(settings)
	if err != nil {
		return err
	}

	done := make(chan struct{})
	go func() {
		// make sure setting is propogated
		_, err = indexSet.Index.WaitTask(task)
		close(done)
	}()

	select {
	case <-done:
		return err
	case <-time.After(time.Second * 30):
		return errors.New("couldnt update index settings in 30 second")
	}
}
<|endoftext|>