<commit_before>package forth

// Source: exercism/problem-specifications
// Commit: 3cb5e76 forth: Remove test for empty input (#976)
// Problem Specifications Version: 1.3.0

type testGroup struct {
	group string
	tests []testCase
}

type testCase struct {
	description string
	input       []string
	expected    []int // nil slice indicates error expected.
}

var testGroups = []testGroup{
	{
		group: "parsing and numbers",
		tests: []testCase{
			{
				"numbers just get pushed onto the stack",
				[]string{"1 2 3 4 5"},
				[]int{1, 2, 3, 4, 5},
			},
		},
	},
	{
		group: "addition",
		tests: []testCase{
			{
				"can add two numbers",
				[]string{"1 2 +"},
				[]int{3},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"+"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 +"},
				[]int(nil),
			},
		},
	},
	{
		group: "subtraction",
		tests: []testCase{
			{
				"can subtract two numbers",
				[]string{"3 4 -"},
				[]int{-1},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"-"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 -"},
				[]int(nil),
			},
		},
	},
	{
		group: "multiplication",
		tests: []testCase{
			{
				"can multiply two numbers",
				[]string{"2 4 *"},
				[]int{8},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"*"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 *"},
				[]int(nil),
			},
		},
	},
	{
		group: "division",
		tests: []testCase{
			{
				"can divide two numbers",
				[]string{"12 3 /"},
				[]int{4},
			},
			{
				"performs integer division",
				[]string{"8 3 /"},
				[]int{2},
			},
			{
				"errors if dividing by zero",
				[]string{"4 0 /"},
				[]int(nil),
			},
			{
				"errors if there is nothing on the stack",
				[]string{"/"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 /"},
				[]int(nil),
			},
		},
	},
	{
		group: "combined arithmetic",
		tests: []testCase{
			{
				"addition and subtraction",
				[]string{"1 2 + 4 -"},
				[]int{-1},
			},
			{
				"multiplication and division",
				[]string{"2 4 * 3 /"},
				[]int{2},
			},
		},
	},
	{
		group: "dup",
		tests: []testCase{
			{
				"copies the top value on the stack",
				[]string{"1 DUP"},
				[]int{1, 1},
			},
			{
				"is case-insensitive",
				[]string{"1 2 Dup"},
				[]int{1, 2, 2},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"dup"},
				[]int(nil),
			},
		},
	},
	{
		group: "drop",
		tests: []testCase{
			{
				"removes the top value on the stack if it is the only one",
				[]string{"1 drop"},
				[]int{},
			},
			{
				"removes the top value on the stack if it is not the only one",
				[]string{"1 2 drop"},
				[]int{1},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"drop"},
				[]int(nil),
			},
		},
	},
	{
		group: "swap",
		tests: []testCase{
			{
				"swaps the top two values on the stack if they are the only ones",
				[]string{"1 2 swap"},
				[]int{2, 1},
			},
			{
				"swaps the top two values on the stack if they are not the only ones",
				[]string{"1 2 3 swap"},
				[]int{1, 3, 2},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"swap"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 swap"},
				[]int(nil),
			},
		},
	},
	{
		group: "over",
		tests: []testCase{
			{
				"copies the second element if there are only two",
				[]string{"1 2 over"},
				[]int{1, 2, 1},
			},
			{
				"copies the second element if there are more than two",
				[]string{"1 2 3 over"},
				[]int{1, 2, 3, 2},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"over"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 over"},
				[]int(nil),
			},
		},
	},
	{
		group: "user-defined words",
		tests: []testCase{
			{
				"can consist of built-in words",
				[]string{": dup-twice dup dup ;", "1 dup-twice"},
				[]int{1, 1, 1},
			},
			{
				"execute in the right order",
				[]string{": countup 1 2 3 ;", "countup"},
				[]int{1, 2, 3},
			},
			{
				"can override other user-defined words",
				[]string{": foo dup ;", ": foo dup dup ;", "1 foo"},
				[]int{1, 1, 1},
			},
			{
				"can override built-in words",
				[]string{": swap dup ;", "1 swap"},
				[]int{1, 1},
			},
			{
				"can override built-in operators",
				[]string{": + * ;", "3 4 +"},
				[]int{12},
			},
			{
				"cannot redefine numbers",
				[]string{": 1 2 ;"},
				[]int(nil),
			},
			{
				"errors if executing a non-existent word",
				[]string{"foo"},
				[]int(nil),
			},
		},
	},
}
<commit_msg>forth: run generator to new cases (#955)<commit_after>package forth

// Source: exercism/problem-specifications
// Commit: 9bf041b forth: Add tests for case-insensitivity (#979)
// Problem Specifications Version: 1.4.0

type testGroup struct {
	group string
	tests []testCase
}

type testCase struct {
	description string
	input       []string
	expected    []int // nil slice indicates error expected.
}

var testGroups = []testGroup{
	{
		group: "parsing and numbers",
		tests: []testCase{
			{
				"numbers just get pushed onto the stack",
				[]string{"1 2 3 4 5"},
				[]int{1, 2, 3, 4, 5},
			},
		},
	},
	{
		group: "addition",
		tests: []testCase{
			{
				"can add two numbers",
				[]string{"1 2 +"},
				[]int{3},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"+"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 +"},
				[]int(nil),
			},
		},
	},
	{
		group: "subtraction",
		tests: []testCase{
			{
				"can subtract two numbers",
				[]string{"3 4 -"},
				[]int{-1},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"-"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 -"},
				[]int(nil),
			},
		},
	},
	{
		group: "multiplication",
		tests: []testCase{
			{
				"can multiply two numbers",
				[]string{"2 4 *"},
				[]int{8},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"*"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 *"},
				[]int(nil),
			},
		},
	},
	{
		group: "division",
		tests: []testCase{
			{
				"can divide two numbers",
				[]string{"12 3 /"},
				[]int{4},
			},
			{
				"performs integer division",
				[]string{"8 3 /"},
				[]int{2},
			},
			{
				"errors if dividing by zero",
				[]string{"4 0 /"},
				[]int(nil),
			},
			{
				"errors if there is nothing on the stack",
				[]string{"/"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 /"},
				[]int(nil),
			},
		},
	},
	{
		group: "combined arithmetic",
		tests: []testCase{
			{
				"addition and subtraction",
				[]string{"1 2 + 4 -"},
				[]int{-1},
			},
			{
				"multiplication and division",
				[]string{"2 4 * 3 /"},
				[]int{2},
			},
		},
	},
	{
		group: "dup",
		tests: []testCase{
			{
				"copies a value on the stack",
				[]string{"1 dup"},
				[]int{1, 1},
			},
			{
				"copies the top value on the stack",
				[]string{"1 2 dup"},
				[]int{1, 2, 2},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"dup"},
				[]int(nil),
			},
		},
	},
	{
		group: "drop",
		tests: []testCase{
			{
				"removes the top value on the stack if it is the only one",
				[]string{"1 drop"},
				[]int{},
			},
			{
				"removes the top value on the stack if it is not the only one",
				[]string{"1 2 drop"},
				[]int{1},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"drop"},
				[]int(nil),
			},
		},
	},
	{
		group: "swap",
		tests: []testCase{
			{
				"swaps the top two values on the stack if they are the only ones",
				[]string{"1 2 swap"},
				[]int{2, 1},
			},
			{
				"swaps the top two values on the stack if they are not the only ones",
				[]string{"1 2 3 swap"},
				[]int{1, 3, 2},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"swap"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 swap"},
				[]int(nil),
			},
		},
	},
	{
		group: "over",
		tests: []testCase{
			{
				"copies the second element if there are only two",
				[]string{"1 2 over"},
				[]int{1, 2, 1},
			},
			{
				"copies the second element if there are more than two",
				[]string{"1 2 3 over"},
				[]int{1, 2, 3, 2},
			},
			{
				"errors if there is nothing on the stack",
				[]string{"over"},
				[]int(nil),
			},
			{
				"errors if there is only one value on the stack",
				[]string{"1 over"},
				[]int(nil),
			},
		},
	},
	{
		group: "user-defined words",
		tests: []testCase{
			{
				"can consist of built-in words",
				[]string{": dup-twice dup dup ;", "1 dup-twice"},
				[]int{1, 1, 1},
			},
			{
				"execute in the right order",
				[]string{": countup 1 2 3 ;", "countup"},
				[]int{1, 2, 3},
			},
			{
				"can override other user-defined words",
				[]string{": foo dup ;", ": foo dup dup ;", "1 foo"},
				[]int{1, 1, 1},
			},
			{
				"can override built-in words",
				[]string{": swap dup ;", "1 swap"},
				[]int{1, 1},
			},
			{
				"can override built-in operators",
				[]string{": + * ;", "3 4 +"},
				[]int{12},
			},
			{
				"cannot redefine numbers",
				[]string{": 1 2 ;"},
				[]int(nil),
			},
			{
				"errors if executing a non-existent word",
				[]string{"foo"},
				[]int(nil),
			},
		},
	},
	{
		group: "case-insensitivity",
		tests: []testCase{
			{
				"DUP is case-insensitive",
				[]string{"1 DUP Dup dup"},
				[]int{1, 1, 1, 1},
			},
			{
				"DROP is case-insensitive",
				[]string{"1 2 3 4 DROP Drop drop"},
				[]int{1},
			},
			{
				"SWAP is case-insensitive",
				[]string{"1 2 SWAP 3 Swap 4 swap"},
				[]int{2, 3, 4, 1},
			},
			{
				"OVER is case-insensitive",
				[]string{"1 2 OVER Over over"},
				[]int{1, 2, 1, 2, 1},
			},
			{
				"user-defined words are case-insensitive",
				[]string{": foo dup ;", "1 FOO Foo foo"},
				[]int{1, 1, 1, 1},
			},
			{
				"definitions are case-insensitive",
				[]string{": SWAP DUP Dup dup ;", "1 swap"},
				[]int{1, 1, 1, 1},
			},
		},
	},
}
<|endoftext|>


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

// +build linux

package rawfile

import (
	"syscall"

	"github.com/google/netstack/tcpip"
)

var translations = map[syscall.Errno]*tcpip.Error{
	syscall.EEXIST:        tcpip.ErrDuplicateAddress,
	syscall.ENETUNREACH:   tcpip.ErrNoRoute,
	syscall.EINVAL:        tcpip.ErrInvalidEndpointState,
	syscall.EALREADY:      tcpip.ErrAlreadyConnecting,
	syscall.EISCONN:       tcpip.ErrAlreadyConnected,
	syscall.EADDRINUSE:    tcpip.ErrPortInUse,
	syscall.EADDRNOTAVAIL: tcpip.ErrBadLocalAddress,
	syscall.EPIPE:         tcpip.ErrClosedForSend,
	syscall.EWOULDBLOCK:   tcpip.ErrWouldBlock,
	syscall.ECONNREFUSED:  tcpip.ErrConnectionRefused,
	syscall.ETIMEDOUT:     tcpip.ErrTimeout,
	syscall.EINPROGRESS:   tcpip.ErrConnectStarted,
	syscall.EDESTADDRREQ:  tcpip.ErrDestinationRequired,
	syscall.ENOTSUP:       tcpip.ErrNotSupported,
	syscall.ENOTTY:        tcpip.ErrQueueSizeNotSupported,
	syscall.ENOTCONN:      tcpip.ErrNotConnected,
	syscall.ECONNRESET:    tcpip.ErrConnectionReset,
	syscall.ECONNABORTED:  tcpip.ErrConnectionAborted,
	syscall.EMSGSIZE:      tcpip.ErrMessageTooLong,
	syscall.ENOBUFS:       tcpip.ErrNoBufferSpace,
}

// TranslateErrno translate an errno from the syscall package into a
// *tcpip.Error.
//
// Not all errnos are supported and this function will panic on unreconized
// errnos.
func TranslateErrno(e syscall.Errno) *tcpip.Error {
	if err, ok := translations[e]; ok {
		return err
	}
	return tcpip.ErrInvalidEndpointState
}
<commit_msg>Use syserr style error translation in netstack's rawfile<commit_after>// Copyright 2018 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.

// +build linux

package rawfile

import (
	"fmt"
	"syscall"

	"github.com/google/netstack/tcpip"
)

const maxErrno = 134

var translations [maxErrno]*tcpip.Error

// TranslateErrno translate an errno from the syscall package into a
// *tcpip.Error.
//
// Valid, but unreconigized errnos will be translated to
// tcpip.ErrInvalidEndpointState (EINVAL). Panics on invalid errnos.
func TranslateErrno(e syscall.Errno) *tcpip.Error {
	if err := translations[e]; err != nil {
		return err
	}
	return tcpip.ErrInvalidEndpointState
}

func addTranslation(host syscall.Errno, trans *tcpip.Error) {
	if translations[host] != nil {
		panic(fmt.Sprintf("duplicate translation for host errno %q (%d)", host.Error(), host))
	}
	translations[host] = trans
}

func init() {
	addTranslation(syscall.EEXIST, tcpip.ErrDuplicateAddress)
	addTranslation(syscall.ENETUNREACH, tcpip.ErrNoRoute)
	addTranslation(syscall.EINVAL, tcpip.ErrInvalidEndpointState)
	addTranslation(syscall.EALREADY, tcpip.ErrAlreadyConnecting)
	addTranslation(syscall.EISCONN, tcpip.ErrAlreadyConnected)
	addTranslation(syscall.EADDRINUSE, tcpip.ErrPortInUse)
	addTranslation(syscall.EADDRNOTAVAIL, tcpip.ErrBadLocalAddress)
	addTranslation(syscall.EPIPE, tcpip.ErrClosedForSend)
	addTranslation(syscall.EWOULDBLOCK, tcpip.ErrWouldBlock)
	addTranslation(syscall.ECONNREFUSED, tcpip.ErrConnectionRefused)
	addTranslation(syscall.ETIMEDOUT, tcpip.ErrTimeout)
	addTranslation(syscall.EINPROGRESS, tcpip.ErrConnectStarted)
	addTranslation(syscall.EDESTADDRREQ, tcpip.ErrDestinationRequired)
	addTranslation(syscall.ENOTSUP, tcpip.ErrNotSupported)
	addTranslation(syscall.ENOTTY, tcpip.ErrQueueSizeNotSupported)
	addTranslation(syscall.ENOTCONN, tcpip.ErrNotConnected)
	addTranslation(syscall.ECONNRESET, tcpip.ErrConnectionReset)
	addTranslation(syscall.ECONNABORTED, tcpip.ErrConnectionAborted)
	addTranslation(syscall.EMSGSIZE, tcpip.ErrMessageTooLong)
	addTranslation(syscall.ENOBUFS, tcpip.ErrNoBufferSpace)
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"math"
	"math/rand"
	"net/http"
	"os"
	"sort"
	"strings"
	"sync"
	"time"
)

var (
	numUser           = flag.Int("numuser", 1, "number of users hitting simultaneously")
	numSec            = flag.Float64("numsec", 10, "number of request per user")
	serverAddr        = flag.String("ip", ":8080", "IP addr of server")
	countC            chan int
	jsonP             chan float64
	serverP           chan float64
	parsingP          chan float64
	totalP            chan float64
	latC              chan float64
	actors, directors []string
	serverList        []string
)

var qa1 = `{
		  debug(_xid_:`
var qa2 = `) {
			    type.object.name.en
			    film.actor.film {
				      film.performance.film {
					        type.object.name.en
				      }
			    }
		  }
		}`
var qd1 = `{
			  debug(_xid_:`
var qd2 = `) {
					    type.object.name.en
					    film.director.film  {
							      film.film.genre {
							        type.object.name.en
							      }
					    }
			  }
		}`

func runUser(wg *sync.WaitGroup) {
	var proT, parT, jsonT, totT time.Duration
	var count int

	client := &http.Client{Transport: &http.Transport{
		MaxIdleConnsPerHost: 100,
	}}
	var dat map[string]interface{}
	var latency map[string]interface{}

	tix := time.Now()

	for time.Now().Sub(tix).Seconds() < *numSec {
		var choose = rand.Intn(2)
		var query string
		if choose == 1 {
			var ridx = rand.Intn(len(actors))
			query = qa1 + actors[ridx] + qa2
		} else {
			var ridx = rand.Intn(len(directors))
			query = qd1 + directors[ridx] + qd2
		}

		r, _ := http.NewRequest("POST", serverList[rand.Intn(len(serverList))], bytes.NewBufferString(query))
		resp, err := client.Do(r)

		count++

		if err != nil {
			log.Fatal(err)
		} else {
			body, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				log.Fatalf("Couldn't parse response body. %+v", err)
			}
			resp.Body.Close()
			err = json.Unmarshal(body, &dat)
			if err != nil {
				log.Fatal(err)
			}

			temp := dat["server_latency"]
			latency = temp.(map[string]interface{})

			pro, _ := time.ParseDuration(latency["processing"].(string))
			proT += pro
			js, _ := time.ParseDuration(latency["json"].(string))
			jsonT += js
			par, _ := time.ParseDuration(latency["parsing"].(string))
			parT += par

			tot, _ := time.ParseDuration(latency["total"].(string))
			totT += tot

			latC <- tot.Seconds()
		}
	}
	countC <- count
	totalP <- totT.Seconds()

	wg.Done()
}

func main() {
	flag.Parse()
	var meanLat, sdLat, serTi, jsonTi, parTi, totTi float64
	var totCount int
	var wg sync.WaitGroup
	var allLat []float64
	serverList = strings.Split(*serverAddr, ",")
	actorfile, err := os.Open("listofactors")
	directorfile, err1 := os.Open("listofdirectors")
	if err != nil || err1 != nil {
		return
	}
	defer actorfile.Close()
	defer directorfile.Close()

	scanner := bufio.NewScanner(actorfile)
	for scanner.Scan() {
		actors = append(actors, scanner.Text())
	}
	scanner = bufio.NewScanner(directorfile)
	for scanner.Scan() {
		directors = append(directors, scanner.Text())
	}

	countC = make(chan int, 5*(*numUser))
	serverP = make(chan float64, 5*(*numUser))
	totalP = make(chan float64, 5*(*numUser))
	parsingP = make(chan float64, 5*(*numUser))
	jsonP = make(chan float64, 5*(*numUser))
	latC = make(chan float64, 100000)

	go func() {
		for t := range latC {
			allLat = append(allLat, t)
		}
	}()
	wg.Add(*numUser)
	fmt.Println("First run")
	for i := 0; i < *numUser; i++ {
		go runUser(&wg)
	}

	wg.Wait()
	time.Sleep(1 * time.Second)
	wg.Add(*numUser)
	fmt.Println("Second run")
	for i := 0; i < *numUser; i++ {
		go runUser(&wg)
	}
	wg.Wait()
	time.Sleep(1 * time.Second)
	wg.Add(*numUser)
	fmt.Println("Third run")
	for i := 0; i < *numUser; i++ {
		go runUser(&wg)
	}
	wg.Wait()

	close(countC)
	close(serverP)
	close(parsingP)
	close(jsonP)
	close(totalP)
	close(latC)
	fmt.Println("DONE!")
	for it := range countC {
		totCount += it
	}
	for it := range serverP {
		serTi += it
	}
	for it := range parsingP {
		parTi += it
	}
	for it := range jsonP {
		jsonTi += it
	}
	for it := range totalP {
		totTi += it
	}

	meanLat = serTi / float64(totCount)
	for _, it := range allLat {
		sdLat += math.Pow((it - meanLat), 2)
	}
	sort.Float64s(allLat)
	sdLat = math.Sqrt(sdLat / float64(len(allLat)-1))

	fmt.Println("------------------------------------------------------------------------")
	fmt.Println("\n NumUser :", *numUser)
	fmt.Println("Throughput (num request per second) : ", float64(totCount)/(3*(*numSec)))
	fmt.Println("Total number of queries : ", totCount)
	fmt.Println("Avg time (ms) : ", 1000*totTi/float64(totCount))
	fmt.Println("95 percentile latency : ", 1000*allLat[int(len(allLat)/2)], 1000*allLat[int(95*len(allLat)/100)])
	fmt.Println("Min, Max : ", 1000*allLat[0], 1000*allLat[len(allLat)-1])
	fmt.Println("------------------------------------------------------------------------")
}
<commit_msg>change default port<commit_after>package main

import (
	"bufio"
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"math"
	"math/rand"
	"net/http"
	"os"
	"sort"
	"strings"
	"sync"
	"time"
)

var (
	numUser           = flag.Int("numuser", 1, "number of users hitting simultaneously")
	numSec            = flag.Float64("numsec", 10, "number of request per user")
	serverAddr        = flag.String("ip", ":10001", "IP addr of server")
	countC            chan int
	jsonP             chan float64
	serverP           chan float64
	parsingP          chan float64
	totalP            chan float64
	latC              chan float64
	actors, directors []string
	serverList        []string
)

var qa1 = `{
		  debug(_xid_:`
var qa2 = `) {
			    type.object.name.en
			    film.actor.film {
				      film.performance.film {
					        type.object.name.en
				      }
			    }
		  }
		}`
var qd1 = `{
			  debug(_xid_:`
var qd2 = `) {
					    type.object.name.en
					    film.director.film  {
							      film.film.genre {
							        type.object.name.en
							      }
					    }
			  }
		}`

func runUser(wg *sync.WaitGroup) {
	var proT, parT, jsonT, totT time.Duration
	var count int

	client := &http.Client{Transport: &http.Transport{
		MaxIdleConnsPerHost: 100,
	}}
	var dat map[string]interface{}
	var latency map[string]interface{}

	tix := time.Now()

	for time.Now().Sub(tix).Seconds() < *numSec {
		var choose = rand.Intn(2)
		var query string
		if choose == 1 {
			var ridx = rand.Intn(len(actors))
			query = qa1 + actors[ridx] + qa2
		} else {
			var ridx = rand.Intn(len(directors))
			query = qd1 + directors[ridx] + qd2
		}

		r, _ := http.NewRequest("POST", serverList[rand.Intn(len(serverList))], bytes.NewBufferString(query))
		resp, err := client.Do(r)

		count++

		if err != nil {
			log.Fatal(err)
		} else {
			body, err := ioutil.ReadAll(resp.Body)
			if err != nil {
				log.Fatalf("Couldn't parse response body. %+v", err)
			}
			resp.Body.Close()
			err = json.Unmarshal(body, &dat)
			if err != nil {
				log.Fatal(err)
			}

			temp := dat["server_latency"]
			latency = temp.(map[string]interface{})

			pro, _ := time.ParseDuration(latency["processing"].(string))
			proT += pro
			js, _ := time.ParseDuration(latency["json"].(string))
			jsonT += js
			par, _ := time.ParseDuration(latency["parsing"].(string))
			parT += par

			tot, _ := time.ParseDuration(latency["total"].(string))
			totT += tot

			latC <- tot.Seconds()
		}
	}
	countC <- count
	totalP <- totT.Seconds()

	wg.Done()
}

func main() {
	flag.Parse()
	var meanLat, sdLat, serTi, jsonTi, parTi, totTi float64
	var totCount int
	var wg sync.WaitGroup
	var allLat []float64
	serverList = strings.Split(*serverAddr, ",")
	actorfile, err := os.Open("listofactors")
	directorfile, err1 := os.Open("listofdirectors")
	if err != nil || err1 != nil {
		return
	}
	defer actorfile.Close()
	defer directorfile.Close()

	scanner := bufio.NewScanner(actorfile)
	for scanner.Scan() {
		actors = append(actors, scanner.Text())
	}
	scanner = bufio.NewScanner(directorfile)
	for scanner.Scan() {
		directors = append(directors, scanner.Text())
	}

	countC = make(chan int, 5*(*numUser))
	serverP = make(chan float64, 5*(*numUser))
	totalP = make(chan float64, 5*(*numUser))
	parsingP = make(chan float64, 5*(*numUser))
	jsonP = make(chan float64, 5*(*numUser))
	latC = make(chan float64, 100000)

	go func() {
		for t := range latC {
			allLat = append(allLat, t)
		}
	}()
	wg.Add(*numUser)
	fmt.Println("First run")
	for i := 0; i < *numUser; i++ {
		go runUser(&wg)
	}

	wg.Wait()
	time.Sleep(1 * time.Second)
	wg.Add(*numUser)
	fmt.Println("Second run")
	for i := 0; i < *numUser; i++ {
		go runUser(&wg)
	}
	wg.Wait()
	time.Sleep(1 * time.Second)
	wg.Add(*numUser)
	fmt.Println("Third run")
	for i := 0; i < *numUser; i++ {
		go runUser(&wg)
	}
	wg.Wait()

	close(countC)
	close(serverP)
	close(parsingP)
	close(jsonP)
	close(totalP)
	close(latC)
	fmt.Println("DONE!")
	for it := range countC {
		totCount += it
	}
	for it := range serverP {
		serTi += it
	}
	for it := range parsingP {
		parTi += it
	}
	for it := range jsonP {
		jsonTi += it
	}
	for it := range totalP {
		totTi += it
	}

	meanLat = serTi / float64(totCount)
	for _, it := range allLat {
		sdLat += math.Pow((it - meanLat), 2)
	}
	sort.Float64s(allLat)
	sdLat = math.Sqrt(sdLat / float64(len(allLat)-1))

	fmt.Println("------------------------------------------------------------------------")
	fmt.Println("\n NumUser :", *numUser)
	fmt.Println("Throughput (num request per second) : ", float64(totCount)/(3*(*numSec)))
	fmt.Println("Total number of queries : ", totCount)
	fmt.Println("Avg time (ms) : ", 1000*totTi/float64(totCount))
	fmt.Println("95 percentile latency : ", 1000*allLat[int(len(allLat)/2)], 1000*allLat[int(95*len(allLat)/100)])
	fmt.Println("Min, Max : ", 1000*allLat[0], 1000*allLat[len(allLat)-1])
	fmt.Println("------------------------------------------------------------------------")
}
<|endoftext|>


<commit_before>package copper

import (
	"fmt"
	"sort"
)

type serverPublicationByPriority []*serverPublication

func (p serverPublicationByPriority) Len() int      { return len(p) }
func (p serverPublicationByPriority) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p serverPublicationByPriority) Less(i, j int) bool {
	return p[i].settings.Priority < p[j].settings.Priority
}
func (p serverPublicationByPriority) Sort() { sort.Sort(p) }

type serverPeerRemotesByPriority []*serverPeerRemote

func (p serverPeerRemotesByPriority) Len() int      { return len(p) }
func (p serverPeerRemotesByPriority) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p serverPeerRemotesByPriority) Less(i, j int) bool {
	return p[i].settings.Priority < p[j].settings.Priority
}
func (p serverPeerRemotesByPriority) Sort() { sort.Sort(p) }

type serverSubscriptionOption struct {
	option *SubscribeOption
	route  *serverRoute
	local  serverPublicationByPriority
	remote serverPeerRemotesByPriority

	localPriority  uint32
	remoteCount    int
	remotePriority uint32
}

var _ endpointReference = &serverSubscriptionOption{}

func (o *serverSubscriptionOption) getEndpointsLocked() []Endpoint {
	if o.route != nil {
		return o.route.getEndpointsLocked()
	}
	if len(o.local) > 0 && o.localPriority <= o.remotePriority {
		return o.local[0].getEndpointsLocked()
	}
	var result []Endpoint
	for _, remote := range o.remote {
		if remote.settings.Priority == o.remotePriority {
			result = append(result, remote.getEndpointsLocked()...)
		}
	}
	return result
}

func (o *serverSubscriptionOption) handleRequestLocked(callback handleRequestCallback) handleRequestStatus {
	if o.route != nil {
		return o.route.handleRequestLocked(callback)
	}
	if len(o.local) > 0 && o.localPriority <= o.remotePriority {
		return o.local[0].handleRequestLocked(callback)
	}
	if o.remoteCount > 0 {
		index := 0
		if o.remoteCount > 1 {
			index = globalRandom.Intn(o.remoteCount)
		}
		return o.remote[index].handleRequestLocked(callback)
	}
	return handleRequestStatusNoRoute
}

func (o *serverSubscriptionOption) isActiveLocked() bool {
	if o.route != nil {
		return true
	}
	if len(o.local) > 0 {
		return true
	}
	if len(o.remote) > 0 {
		return true
	}
	return false
}

func (o *serverSubscriptionOption) updateLocalPriorityLocked() {
	if len(o.local) > 0 {
		o.localPriority = o.local[0].settings.Priority
	} else {
		o.localPriority = 0xffffffff
	}
}

func (o *serverSubscriptionOption) updateRemotePriorityLocked() {
	if len(o.remote) > 0 {
		o.remoteCount = 1
		o.remotePriority = o.remote[0].settings.Priority
		for i := 1; i < len(o.remote); i++ {
			if o.remote[i].settings.Priority != o.remotePriority {
				break
			}
			o.remoteCount++
		}
	} else {
		o.remoteCount = 0
		o.remotePriority = 0xffffffff
	}
}

func (o *serverSubscriptionOption) addRouteLocked(route *serverRoute) bool {
	o.route = route
	return true
}

func (o *serverSubscriptionOption) removeRouteLocked(route *serverRoute) bool {
	if o.route == route {
		o.route = nil
		return true
	}
	return false
}

func (o *serverSubscriptionOption) addPublicationLocked(pub *serverPublication) bool {
	if o.option.MinDistance == 0 {
		// this option allows using local publications
		o.local = append(o.local, pub)
		return true
	}
	return false
}

func (o *serverSubscriptionOption) removePublicationLocked(pub *serverPublication) bool {
	if o.option.MinDistance == 0 {
		// this option allows using local publications
		for index, value := range o.local {
			if value == pub {
				copy(o.local[index:], o.local[index+1:])
				o.local[len(o.local)-1] = nil
				o.local = o.local[:len(o.local)-1]
				return true
			}
		}
	}
	return false
}

func (o *serverSubscriptionOption) addRemoteLocked(remote *serverPeerRemote) bool {
	if o.option.MinDistance <= remote.settings.Distance && remote.settings.Distance <= o.option.MaxDistance {
		// this remote falls under this option's filter
		o.remote = append(o.remote, remote)
		return true
	}
	return false
}

func (o *serverSubscriptionOption) removeRemoteLocked(remote *serverPeerRemote) bool {
	if o.option.MinDistance <= remote.settings.Distance && remote.settings.Distance <= o.option.MaxDistance {
		// this remote falls under this option's filter
		for index, value := range o.remote {
			if value == remote {
				copy(o.local[index:], o.local[index+1:])
				o.local[len(o.local)-1] = nil
				o.local = o.local[:len(o.local)-1]
				return true
			}
		}
	}
	return false
}

type serverSubscription struct {
	owner    *server
	targetID int64
	settings SubscribeSettings

	options []serverSubscriptionOption
	active  int

	indexByName map[string][]int
}

var _ endpointReference = &serverSubscription{}

func (sub *serverSubscription) getEndpointsLocked() []Endpoint {
	if sub.active < len(sub.options) {
		return sub.options[sub.active].getEndpointsLocked()
	}
	// TODO: support upstream
	return nil
}

func (sub *serverSubscription) handleRequestLocked(callback handleRequestCallback) handleRequestStatus {
	if sub.active < len(sub.options) {
		return sub.options[sub.active].handleRequestLocked(callback)
	}
	// TODO: support upstream
	return handleRequestStatusNoRoute
}

func (sub *serverSubscription) isActiveLocked() bool {
	return sub.active < len(sub.options)
}

func (sub *serverSubscription) updateActiveIndexLocked() {
	for index := range sub.options {
		if sub.options[index].isActiveLocked() {
			sub.active = index
			return
		}
	}
	sub.active = len(sub.options)
}

func (sub *serverSubscription) addRouteLocked(route *serverRoute) {
	if sub.settings.DisableRoutes {
		return
	}
	changed := false
	for _, index := range sub.indexByName[route.name] {
		if sub.options[index].addRouteLocked(route) {
			changed = true
		}
	}
	if changed {
		route.subscriptions[sub] = struct{}{}
		sub.updateActiveIndexLocked()
	}
}

func (sub *serverSubscription) removeRouteLocked(route *serverRoute) {
	if sub.settings.DisableRoutes {
		return
	}
	changed := false
	for index := range sub.settings.Options {
		if sub.options[index].removeRouteLocked(route) {
			changed = true
		}
	}
	if changed {
		sub.updateActiveIndexLocked()
	}
}

func (sub *serverSubscription) addPublicationLocked(pub *serverPublication) {
	changed := false
	for _, index := range sub.indexByName[pub.name] {
		if sub.options[index].addPublicationLocked(pub) {
			changed = true
			sub.options[index].local.Sort()
			sub.options[index].updateLocalPriorityLocked()
		}
	}
	if changed {
		pub.subscriptions[sub] = struct{}{}
		sub.updateActiveIndexLocked()
	}
}

func (sub *serverSubscription) removePublicationLocked(pub *serverPublication) {
	changed := false
	for _, index := range sub.indexByName[pub.name] {
		if sub.options[index].removePublicationLocked(pub) {
			changed = true
			sub.options[index].updateLocalPriorityLocked()
		}
	}
	if changed {
		sub.updateActiveIndexLocked()
	}
}

func (sub *serverSubscription) addRemoteLocked(remote *serverPeerRemote) {
	changed := false
	for _, index := range sub.indexByName[remote.name] {
		if sub.options[index].addRemoteLocked(remote) {
			changed = true
			sub.options[index].remote.Sort()
			sub.options[index].updateRemotePriorityLocked()
		}
	}
	if changed {
		remote.subscriptions[sub] = struct{}{}
		sub.updateActiveIndexLocked()
	}
}

func (sub *serverSubscription) removeRemoteLocked(remote *serverPeerRemote) {
	changed := false
	for _, index := range sub.indexByName[remote.name] {
		if sub.options[index].removeRemoteLocked(remote) {
			changed = true
		}
	}
	if changed {
		sub.updateActiveIndexLocked()
	}
}

func (s *server) subscribeLocked(settings SubscribeSettings) (*serverSubscription, error) {
	if len(settings.Options) == 0 {
		return nil, fmt.Errorf("cannot subscribe with 0 options")
	}
	sub := &serverSubscription{
		owner:    s,
		targetID: s.allocateTargetID(),
		settings: settings,

		options: make([]serverSubscriptionOption, len(settings.Options)),
		active:  len(settings.Options),

		indexByName: make(map[string][]int),
	}
	for index := range sub.settings.Options {
		option := &sub.settings.Options[index]
		sub.options[index].option = option
		sub.indexByName[option.Service] = append(sub.indexByName[option.Service], index)
	}
	for name, indexes := range sub.indexByName {
		// Let others know we have an interest in this name
		subs := sub.owner.subsByName[name]
		if subs == nil {
			subs = make(map[*serverSubscription]struct{})
			sub.owner.subsByName[name] = subs
		}
		subs[sub] = struct{}{}

		// Find an existing route, if any
		if !sub.settings.DisableRoutes {
			if route := sub.owner.routeByName[name]; route != nil {
				changed := false
				for _, index := range indexes {
					if sub.options[index].addRouteLocked(route) {
						changed = true
					}
				}
				if changed {
					route.subscriptions[sub] = struct{}{}
				}
			}
		}

		// Find and subscribe to local publications
		for _, pub := range sub.owner.pubsByName[name] {
			changed := false
			for _, index := range indexes {
				if sub.options[index].addPublicationLocked(pub) {
					changed = true
				}
			}
			if changed {
				pub.subscriptions[sub] = struct{}{}
			}
		}

		// Find and subscribe to remote publications
		for _, peer := range s.peers {
			for _, remote := range peer.remotesByName[name] {
				changed := false
				for _, index := range indexes {
					if sub.options[index].addRemoteLocked(remote) {
						changed = true
					}
				}
				if changed {
					remote.subscriptions[sub] = struct{}{}
				}
			}
		}
	}
	for index := range sub.options {
		sub.options[index].local.Sort()
		sub.options[index].updateLocalPriorityLocked()
		sub.options[index].remote.Sort()
		sub.options[index].updateRemotePriorityLocked()
	}
	// TODO: support upstream
	sub.updateActiveIndexLocked()
	return sub, nil
}

func (sub *serverSubscription) unsubscribeLocked() {
	// TODO: support upstream
	for index := range sub.options {
		o := &sub.options[index]
		if o.route != nil {
			delete(o.route.subscriptions, sub)
		}
		for _, pub := range o.local {
			delete(pub.subscriptions, sub)
		}
		for _, remote := range o.remote {
			delete(remote.subscriptions, sub)
		}
		o.route = nil
		o.local = nil
		o.remote = nil
	}
	for name := range sub.indexByName {
		if subs := sub.owner.subsByName[name]; subs != nil {
			delete(subs, sub)
			if len(subs) == 0 {
				delete(sub.owner.subsByName, name)
			}
		}
	}
	sub.active = 0
	sub.options = nil
	sub.indexByName = nil
}
<commit_msg>Fix a panic in removeRemoteLocked<commit_after>package copper

import (
	"fmt"
	"sort"
)

type serverPublicationByPriority []*serverPublication

func (p serverPublicationByPriority) Len() int      { return len(p) }
func (p serverPublicationByPriority) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p serverPublicationByPriority) Less(i, j int) bool {
	return p[i].settings.Priority < p[j].settings.Priority
}
func (p serverPublicationByPriority) Sort() { sort.Sort(p) }

type serverPeerRemotesByPriority []*serverPeerRemote

func (p serverPeerRemotesByPriority) Len() int      { return len(p) }
func (p serverPeerRemotesByPriority) Swap(i, j int) { p[i], p[j] = p[j], p[i] }
func (p serverPeerRemotesByPriority) Less(i, j int) bool {
	return p[i].settings.Priority < p[j].settings.Priority
}
func (p serverPeerRemotesByPriority) Sort() { sort.Sort(p) }

type serverSubscriptionOption struct {
	option *SubscribeOption
	route  *serverRoute
	local  serverPublicationByPriority
	remote serverPeerRemotesByPriority

	localPriority  uint32
	remoteCount    int
	remotePriority uint32
}

var _ endpointReference = &serverSubscriptionOption{}

func (o *serverSubscriptionOption) getEndpointsLocked() []Endpoint {
	if o.route != nil {
		return o.route.getEndpointsLocked()
	}
	if len(o.local) > 0 && o.localPriority <= o.remotePriority {
		return o.local[0].getEndpointsLocked()
	}
	var result []Endpoint
	for _, remote := range o.remote {
		if remote.settings.Priority == o.remotePriority {
			result = append(result, remote.getEndpointsLocked()...)
		}
	}
	return result
}

func (o *serverSubscriptionOption) handleRequestLocked(callback handleRequestCallback) handleRequestStatus {
	if o.route != nil {
		return o.route.handleRequestLocked(callback)
	}
	if len(o.local) > 0 && o.localPriority <= o.remotePriority {
		return o.local[0].handleRequestLocked(callback)
	}
	if o.remoteCount > 0 {
		index := 0
		if o.remoteCount > 1 {
			index = globalRandom.Intn(o.remoteCount)
		}
		return o.remote[index].handleRequestLocked(callback)
	}
	return handleRequestStatusNoRoute
}

func (o *serverSubscriptionOption) isActiveLocked() bool {
	if o.route != nil {
		return true
	}
	if len(o.local) > 0 {
		return true
	}
	if len(o.remote) > 0 {
		return true
	}
	return false
}

func (o *serverSubscriptionOption) updateLocalPriorityLocked() {
	if len(o.local) > 0 {
		o.localPriority = o.local[0].settings.Priority
	} else {
		o.localPriority = 0xffffffff
	}
}

func (o *serverSubscriptionOption) updateRemotePriorityLocked() {
	if len(o.remote) > 0 {
		o.remoteCount = 1
		o.remotePriority = o.remote[0].settings.Priority
		for i := 1; i < len(o.remote); i++ {
			if o.remote[i].settings.Priority != o.remotePriority {
				break
			}
			o.remoteCount++
		}
	} else {
		o.remoteCount = 0
		o.remotePriority = 0xffffffff
	}
}

func (o *serverSubscriptionOption) addRouteLocked(route *serverRoute) bool {
	o.route = route
	return true
}

func (o *serverSubscriptionOption) removeRouteLocked(route *serverRoute) bool {
	if o.route == route {
		o.route = nil
		return true
	}
	return false
}

func (o *serverSubscriptionOption) addPublicationLocked(pub *serverPublication) bool {
	if o.option.MinDistance == 0 {
		// this option allows using local publications
		o.local = append(o.local, pub)
		return true
	}
	return false
}

func (o *serverSubscriptionOption) removePublicationLocked(pub *serverPublication) bool {
	if o.option.MinDistance == 0 {
		// this option allows using local publications
		for index, value := range o.local {
			if value == pub {
				copy(o.local[index:], o.local[index+1:])
				o.local[len(o.local)-1] = nil
				o.local = o.local[:len(o.local)-1]
				return true
			}
		}
	}
	return false
}

func (o *serverSubscriptionOption) addRemoteLocked(remote *serverPeerRemote) bool {
	if o.option.MinDistance <= remote.settings.Distance && remote.settings.Distance <= o.option.MaxDistance {
		// this remote falls under this option's filter
		o.remote = append(o.remote, remote)
		return true
	}
	return false
}

func (o *serverSubscriptionOption) removeRemoteLocked(remote *serverPeerRemote) bool {
	if o.option.MinDistance <= remote.settings.Distance && remote.settings.Distance <= o.option.MaxDistance {
		// this remote falls under this option's filter
		for index, value := range o.remote {
			if value == remote {
				copy(o.remote[index:], o.remote[index+1:])
				o.remote[len(o.remote)-1] = nil
				o.remote = o.remote[:len(o.remote)-1]
				return true
			}
		}
	}
	return false
}

type serverSubscription struct {
	owner    *server
	targetID int64
	settings SubscribeSettings

	options []serverSubscriptionOption
	active  int

	indexByName map[string][]int
}

var _ endpointReference = &serverSubscription{}

func (sub *serverSubscription) getEndpointsLocked() []Endpoint {
	if sub.active < len(sub.options) {
		return sub.options[sub.active].getEndpointsLocked()
	}
	// TODO: support upstream
	return nil
}

func (sub *serverSubscription) handleRequestLocked(callback handleRequestCallback) handleRequestStatus {
	if sub.active < len(sub.options) {
		return sub.options[sub.active].handleRequestLocked(callback)
	}
	// TODO: support upstream
	return handleRequestStatusNoRoute
}

func (sub *serverSubscription) isActiveLocked() bool {
	return sub.active < len(sub.options)
}

func (sub *serverSubscription) updateActiveIndexLocked() {
	for index := range sub.options {
		if sub.options[index].isActiveLocked() {
			sub.active = index
			return
		}
	}
	sub.active = len(sub.options)
}

func (sub *serverSubscription) addRouteLocked(route *serverRoute) {
	if sub.settings.DisableRoutes {
		return
	}
	changed := false
	for _, index := range sub.indexByName[route.name] {
		if sub.options[index].addRouteLocked(route) {
			changed = true
		}
	}
	if changed {
		route.subscriptions[sub] = struct{}{}
		sub.updateActiveIndexLocked()
	}
}

func (sub *serverSubscription) removeRouteLocked(route *serverRoute) {
	if sub.settings.DisableRoutes {
		return
	}
	changed := false
	for index := range sub.settings.Options {
		if sub.options[index].removeRouteLocked(route) {
			changed = true
		}
	}
	if changed {
		sub.updateActiveIndexLocked()
	}
}

func (sub *serverSubscription) addPublicationLocked(pub *serverPublication) {
	changed := false
	for _, index := range sub.indexByName[pub.name] {
		if sub.options[index].addPublicationLocked(pub) {
			changed = true
			sub.options[index].local.Sort()
			sub.options[index].updateLocalPriorityLocked()
		}
	}
	if changed {
		pub.subscriptions[sub] = struct{}{}
		sub.updateActiveIndexLocked()
	}
}

func (sub *serverSubscription) removePublicationLocked(pub *serverPublication) {
	changed := false
	for _, index := range sub.indexByName[pub.name] {
		if sub.options[index].removePublicationLocked(pub) {
			changed = true
			sub.options[index].updateLocalPriorityLocked()
		}
	}
	if changed {
		sub.updateActiveIndexLocked()
	}
}

func (sub *serverSubscription) addRemoteLocked(remote *serverPeerRemote) {
	changed := false
	for _, index := range sub.indexByName[remote.name] {
		if sub.options[index].addRemoteLocked(remote) {
			changed = true
			sub.options[index].remote.Sort()
			sub.options[index].updateRemotePriorityLocked()
		}
	}
	if changed {
		remote.subscriptions[sub] = struct{}{}
		sub.updateActiveIndexLocked()
	}
}

func (sub *serverSubscription) removeRemoteLocked(remote *serverPeerRemote) {
	changed := false
	for _, index := range sub.indexByName[remote.name] {
		if sub.options[index].removeRemoteLocked(remote) {
			changed = true
		}
	}
	if changed {
		sub.updateActiveIndexLocked()
	}
}

func (s *server) subscribeLocked(settings SubscribeSettings) (*serverSubscription, error) {
	if len(settings.Options) == 0 {
		return nil, fmt.Errorf("cannot subscribe with 0 options")
	}
	sub := &serverSubscription{
		owner:    s,
		targetID: s.allocateTargetID(),
		settings: settings,

		options: make([]serverSubscriptionOption, len(settings.Options)),
		active:  len(settings.Options),

		indexByName: make(map[string][]int),
	}
	for index := range sub.settings.Options {
		option := &sub.settings.Options[index]
		sub.options[index].option = option
		sub.indexByName[option.Service] = append(sub.indexByName[option.Service], index)
	}
	for name, indexes := range sub.indexByName {
		// Let others know we have an interest in this name
		subs := sub.owner.subsByName[name]
		if subs == nil {
			subs = make(map[*serverSubscription]struct{})
			sub.owner.subsByName[name] = subs
		}
		subs[sub] = struct{}{}

		// Find an existing route, if any
		if !sub.settings.DisableRoutes {
			if route := sub.owner.routeByName[name]; route != nil {
				changed := false
				for _, index := range indexes {
					if sub.options[index].addRouteLocked(route) {
						changed = true
					}
				}
				if changed {
					route.subscriptions[sub] = struct{}{}
				}
			}
		}

		// Find and subscribe to local publications
		for _, pub := range sub.owner.pubsByName[name] {
			changed := false
			for _, index := range indexes {
				if sub.options[index].addPublicationLocked(pub) {
					changed = true
				}
			}
			if changed {
				pub.subscriptions[sub] = struct{}{}
			}
		}

		// Find and subscribe to remote publications
		for _, peer := range s.peers {
			for _, remote := range peer.remotesByName[name] {
				changed := false
				for _, index := range indexes {
					if sub.options[index].addRemoteLocked(remote) {
						changed = true
					}
				}
				if changed {
					remote.subscriptions[sub] = struct{}{}
				}
			}
		}
	}
	for index := range sub.options {
		sub.options[index].local.Sort()
		sub.options[index].updateLocalPriorityLocked()
		sub.options[index].remote.Sort()
		sub.options[index].updateRemotePriorityLocked()
	}
	// TODO: support upstream
	sub.updateActiveIndexLocked()
	return sub, nil
}

func (sub *serverSubscription) unsubscribeLocked() {
	// TODO: support upstream
	for index := range sub.options {
		o := &sub.options[index]
		if o.route != nil {
			delete(o.route.subscriptions, sub)
		}
		for _, pub := range o.local {
			delete(pub.subscriptions, sub)
		}
		for _, remote := range o.remote {
			delete(remote.subscriptions, sub)
		}
		o.route = nil
		o.local = nil
		o.remote = nil
	}
	for name := range sub.indexByName {
		if subs := sub.owner.subsByName[name]; subs != nil {
			delete(subs, sub)
			if len(subs) == 0 {
				delete(sub.owner.subsByName, name)
			}
		}
	}
	sub.active = 0
	sub.options = nil
	sub.indexByName = nil
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"testing"
	"time"
)

const (
	ANY_DB_DRIVER = ""
	TEST_ENDPOINT = "localhost:9999"
	TEST_DB       = "goslow_test"
)

var DATA_SOURCE = map[string]string{
	"sqlite3":  ":memory:",
	"postgres": "postgres://localhost/" + TEST_DB,
}

type TestCase struct {
	createDefaultRules bool
	adminUrlPathPrefix string
	driver             string
	dataSource         string
}

type TestCases []*TestCase

type CheckFunc func(*testing.T, *httptest.Server, *TestCase)

var (
	defaultTestCases = TestCases{
		NewTestCase(true, "", ANY_DB_DRIVER),
	}

	ruleCreationTestCases = TestCases{
		NewTestCase(true, "", ANY_DB_DRIVER),
		NewTestCase(false, "/goslow", ANY_DB_DRIVER),
		NewTestCase(false, "/goslow/", ANY_DB_DRIVER),
		NewTestCase(false, "/te", ANY_DB_DRIVER),
		NewTestCase(false, "/te/", ANY_DB_DRIVER),
		NewTestCase(false, "/composite/path", ANY_DB_DRIVER),
	}
)

func NewTestCase(createDefaultRules bool, adminUrlPathPrefix string, driver string) *TestCase {
	dataSource, knownDriver := DATA_SOURCE[driver]
	if driver != ANY_DB_DRIVER && !knownDriver {
		log.Fatalf("unknown driver: <%s>", driver)
	}
	return &TestCase{
		createDefaultRules: createDefaultRules,
		adminUrlPathPrefix: adminUrlPathPrefix,
		driver:             driver,
		dataSource:         dataSource,
	}
}

func TestZeroSite(t *testing.T) {
	runAll(t, checkZeroSite, defaultTestCases)
}

func runAll(t *testing.T, checkFunc CheckFunc, testCases TestCases) {
	for _, testCase := range runnable(all(testCases)) {
		run(t, checkFunc, testCase)
	}
}

func runnable(testCases TestCases) TestCases {
	runnableTestCases := make(TestCases, 0)
	for _, testCase := range testCases {
		if !testCase.skippable() {
			runnableTestCases = append(runnableTestCases, testCase)
		}
	}
	return runnableTestCases
}

func all(testCases TestCases) TestCases {
	allTestCases := make(TestCases, 0)
	for _, testCase := range testCases {
		if testCase.driver == ANY_DB_DRIVER {
			sqlite3TestCase := NewTestCase(testCase.createDefaultRules, testCase.adminUrlPathPrefix, "sqlite3")
			postgresTestCase := NewTestCase(testCase.createDefaultRules, testCase.adminUrlPathPrefix, "postgres")
			allTestCases = append(allTestCases, sqlite3TestCase)
			allTestCases = append(allTestCases, postgresTestCase)
		} else {
			allTestCases = append(allTestCases, testCase)
		}
	}
	return allTestCases
}

func (testCase *TestCase) skippable() bool {
	return testCase.driver == "postgres" && testing.Short()
}

func run(t *testing.T, checkFunc CheckFunc, testCase *TestCase) {
	if testCase.driver == "postgres" {
		createDb(TEST_DB)
		defer dropDb(TEST_DB)
	}
	goSlowServer := newSubDomainServer(testCase)
	server := httptest.NewServer(goSlowServer)
	defer server.Close()
	defer goSlowServer.storage.db.Close()
	checkFunc(t, server, testCase)
}

func checkZeroSite(t *testing.T, server *httptest.Server, testCase *TestCase) {
	bytesShouldBeEqual(t,
		readBody(GET(server.URL, "/", makeHost("0", TEST_ENDPOINT))),
		DEFAULT_BODY)
}

func TestTooLargeDelay(t *testing.T) {
	runAll(t, checkTooLargeDelay, defaultTestCases)
}

func checkTooLargeDelay(t *testing.T, server *httptest.Server, testCase *TestCase) {
	prefix := testCase.adminUrlPathPrefix
	domain := newDomain(server, join(prefix, "/booya"), []byte("haha"))
	site := getSite(domain)
	resp := addRule(server, &Rule{Site: site, Delay: time.Duration(1000) * time.Second})
	shouldHaveStatusCode(t, http.StatusBadRequest, resp)
	resp = GET(server.URL, "/", domain)
	shouldHaveStatusCode(t, http.StatusNotFound, resp)
}

func TestRedefineBuiltinSites(t *testing.T) {
	runAll(t, checkRedefineBuiltinSites, defaultTestCases)
}

func checkRedefineBuiltinSites(t *testing.T, server *httptest.Server, testCase *TestCase) {
	for _, site := range []string{"0", "99", "500", "create"} {
		resp := addRule(server, &Rule{Site: site, Path: "/test", Body: []byte("hop"), Method: "GET"})
		shouldHaveStatusCode(t, http.StatusForbidden, resp)
	}
}

func TestRedefineNonExistentSite(t *testing.T) {
	runAll(t, checkRedefineNonExistentSite, defaultTestCases)
}

func checkRedefineNonExistentSite(t *testing.T, server *httptest.Server, testCase *TestCase) {
	for _, site := range []string{"", "ha", "admin-500"} {
		resp := addRule(server, &Rule{Site: site})
		shouldHaveStatusCode(t, http.StatusNotFound, resp)
	}
}

func TestDelay(t *testing.T) {
	runAll(t, checkDelay, defaultTestCases)
}

func checkDelay(t *testing.T, server *httptest.Server, testCase *TestCase) {
	shouldRespondIn(t,
		createGET(server.URL, "/", makeHost("0", TEST_ENDPOINT)),
		0, 0.1) // seconds
	shouldRespondIn(t,
		createGET(server.URL, "/", makeHost("1", TEST_ENDPOINT)),
		1, 1.1) // seconds
}

func TestStatus(t *testing.T) {
	runAll(t, checkStatus, defaultTestCases)
}

func checkStatus(t *testing.T, server *httptest.Server, testCase *TestCase) {
	for _, statusCode := range []int{200, 404, 500} {
		resp := GET(server.URL, "/", makeHost(strconv.Itoa(statusCode), TEST_ENDPOINT))
		shouldHaveStatusCode(t, statusCode, resp)
	}
}

func TestRuleCreation(t *testing.T) {
	runAll(t, checkRuleCreationTestCase, ruleCreationTestCases)
}

// TODO: refactor
func checkRuleCreationTestCase(t *testing.T, server *httptest.Server, testCase *TestCase) {
	prefix := testCase.adminUrlPathPrefix
	domain := TEST_ENDPOINT
	site := ""
	if prefix == "" {
		domain = newDomain(server, join(prefix, "/"), []byte("haha"))
		site = getSite(domain)
	} else {
		resp := addRule(server, &Rule{Path: join(prefix, "/"), Body: []byte("haha")})
		shouldHaveStatusCode(t, http.StatusOK, resp)
	}
	bytesShouldBeEqual(t, readBody(GET(server.URL, "/", domain)), []byte("haha"))
	resp := addRule(server, &Rule{Site: site, Path: join(prefix, "/test"), Body: []byte("hop"), Method: "GET"})
	shouldHaveStatusCode(t, http.StatusOK, resp)

	bytesShouldBeEqual(t, readBody(GET(server.URL, "/test", domain)), []byte("hop"))
	resp = POST(server.URL, "/test", domain, []byte(""))
	intShouldBeEqual(t, 404, resp.StatusCode)
	resp = addRule(server, &Rule{Site: site, Path: join(prefix, "/test"), Body: []byte("for POST"), Method: "POST",
		Delay: time.Duration(100) * time.Millisecond})
	shouldHaveStatusCode(t, http.StatusOK, resp)
	bytesShouldBeEqual(t, readBody(GET(server.URL, "/test", domain)), []byte("hop"))
	bytesShouldBeEqual(t, readBody(POST(server.URL, "/test", domain, []byte(""))), []byte("for POST"))
	shouldRespondIn(t, createPOST(server.URL, "/test", domain, []byte("")), 0.1, 0.15)
}

func newSubDomainServer(testCase *TestCase) *Server {
	config := DEFAULT_CONFIG // copies DEFAULT_CONFIG
	config.endpoint = TEST_ENDPOINT
	config.createDefaultRules = testCase.createDefaultRules
	config.adminUrlPathPrefix = testCase.adminUrlPathPrefix
	config.driver = testCase.driver
	config.dataSource = testCase.dataSource
	return NewServer(&config)
}

func GET(url, path, host string) *http.Response {
	req := createGET(url, path, host)
	return do(req)
}

func do(req *http.Request) *http.Response {
	resp, err := new(http.Client).Do(req)
	if err != nil {
		log.Fatal(err)
	}
	return resp
}

func createGET(url, path, host string) *http.Request {
	req, err := http.NewRequest("GET", url+path, nil)
	if err != nil {
		log.Fatal(err)
	}
	req.Host = host
	return req
}

func readBody(resp *http.Response) []byte {
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	return body
}

func makeHost(subdomain, host string) string {
	return fmt.Sprintf("%s.%s", subdomain, host)
}

func bytesShouldBeEqual(t *testing.T, expected, actual []byte) {
	if !bytes.Equal(expected, actual) {
		t.Fatalf("<<%v>> != <<%v>>", string(expected), string(actual))
	}
}

func intShouldBeEqual(t *testing.T, expected, actual int) {
	if expected != actual {
		t.Fatalf("<<%v>> != <<%v>>", expected, actual)
	}
}

func shouldRespondIn(t *testing.T, req *http.Request, minSeconds, maxSeconds float64) {
	start := time.Now()
	resp := do(req)
	readBody(resp)
	duration := time.Since(start)
	minDuration := toDuration(minSeconds)
	maxDuration := toDuration(maxSeconds)
	if duration < minDuration || duration > maxDuration {
		t.Fatalf("%s%s answered in %v. Not in the interval [%v; %v]",
			req.Host, req.URL.Path, duration, minDuration, maxDuration)
	}
}

func shouldHaveStatusCode(t *testing.T, statusCode int, resp *http.Response) {
	intShouldBeEqual(t, statusCode, resp.StatusCode)
}

func toDuration(seconds float64) time.Duration {
	return time.Duration(seconds*1000) * time.Millisecond
}

// TODO: rename, it returns a full domain, not a site
func newDomain(server *httptest.Server, path string, response []byte) string {
	resp := POST(server.URL, fmt.Sprintf("%s?output=short&method=GET", path),
		makeHost("create", TEST_ENDPOINT), response)
	return string(readBody(resp))
}

func POST(url, path, host string, payload []byte) *http.Response {
	req := createPOST(url, path, host, payload)
	return do(req)
}

func createPOST(url, path, host string, payload []byte) *http.Request {
	req, err := http.NewRequest("POST", url+path, bytes.NewReader(payload))
	if err != nil {
		log.Fatal(err)
	}
	req.Host = host
	return req
}

func getSite(domain string) string {
	return strings.Split(domain, ".")[0]
}

// TODO: use normal GET-parameters builder, not Sprintf and string concatenation
func addRule(server *httptest.Server, rule *Rule) *http.Response {
	path := rule.Path
	path += "?method=" + rule.Method
	path += fmt.Sprintf("&delay=%f", rule.Delay.Seconds())
	return POST(server.URL, path, makeHost("admin-"+rule.Site, TEST_ENDPOINT),
		rule.Body)
}

// Wrapper around path.Join. Preserves trailing slash.
func join(elem ...string) string {
	lastElem := elem[len(elem)-1]
	shouldEndWithSlash := strings.HasSuffix(lastElem, "/")
	joined := path.Join(elem...)
	if shouldEndWithSlash && !strings.HasSuffix(joined, "/") {
		joined += "/"
	}
	return joined
}

func createDb(name string) {
	cmd := exec.Command("createdb", name)
	err := cmd.Run()
	if err != nil {
		log.Fatalf("createdb error: %s", err)
	}
}

func dropDb(name string) {
	cmd := exec.Command("dropdb", name)
	err := cmd.Run()
	if err != nil {
		log.Fatalf("dropdb error: %s", err)
	}
}
<commit_msg>Refactor RuleCreation test<commit_after>package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"os/exec"
	"path"
	"strconv"
	"strings"
	"testing"
	"time"
)

const (
	ANY_DB_DRIVER = ""
	TEST_ENDPOINT = "localhost:9999"
	TEST_DB       = "goslow_test"
)

var DATA_SOURCE = map[string]string{
	"sqlite3":  ":memory:",
	"postgres": "postgres://localhost/" + TEST_DB,
}

type TestCase struct {
	createDefaultRules bool
	adminUrlPathPrefix string
	driver             string
	dataSource         string
}

type TestCases []*TestCase

type CheckFunc func(*testing.T, *httptest.Server, *TestCase)

var (
	defaultTestCases = TestCases{
		NewTestCase(true, "", ANY_DB_DRIVER),
	}

	ruleCreationTestCases = TestCases{
		NewTestCase(true, "", ANY_DB_DRIVER),
		NewTestCase(false, "/goslow", ANY_DB_DRIVER),
		NewTestCase(false, "/goslow/", ANY_DB_DRIVER),
		NewTestCase(false, "/te", ANY_DB_DRIVER),
		NewTestCase(false, "/te/", ANY_DB_DRIVER),
		NewTestCase(false, "/composite/path", ANY_DB_DRIVER),
	}
)

func NewTestCase(createDefaultRules bool, adminUrlPathPrefix string, driver string) *TestCase {
	dataSource, knownDriver := DATA_SOURCE[driver]
	if driver != ANY_DB_DRIVER && !knownDriver {
		log.Fatalf("unknown driver: <%s>", driver)
	}
	return &TestCase{
		createDefaultRules: createDefaultRules,
		adminUrlPathPrefix: adminUrlPathPrefix,
		driver:             driver,
		dataSource:         dataSource,
	}
}

func TestZeroSite(t *testing.T) {
	runAll(t, checkZeroSite, defaultTestCases)
}

func runAll(t *testing.T, checkFunc CheckFunc, testCases TestCases) {
	for _, testCase := range runnable(all(testCases)) {
		run(t, checkFunc, testCase)
	}
}

func runnable(testCases TestCases) TestCases {
	runnableTestCases := make(TestCases, 0)
	for _, testCase := range testCases {
		if !testCase.skippable() {
			runnableTestCases = append(runnableTestCases, testCase)
		}
	}
	return runnableTestCases
}

func all(testCases TestCases) TestCases {
	allTestCases := make(TestCases, 0)
	for _, testCase := range testCases {
		if testCase.driver == ANY_DB_DRIVER {
			sqlite3TestCase := NewTestCase(testCase.createDefaultRules, testCase.adminUrlPathPrefix, "sqlite3")
			postgresTestCase := NewTestCase(testCase.createDefaultRules, testCase.adminUrlPathPrefix, "postgres")
			allTestCases = append(allTestCases, sqlite3TestCase)
			allTestCases = append(allTestCases, postgresTestCase)
		} else {
			allTestCases = append(allTestCases, testCase)
		}
	}
	return allTestCases
}

func (testCase *TestCase) skippable() bool {
	return testCase.driver == "postgres" && testing.Short()
}

func run(t *testing.T, checkFunc CheckFunc, testCase *TestCase) {
	if testCase.driver == "postgres" {
		createDb(TEST_DB)
		defer dropDb(TEST_DB)
	}
	goSlowServer := newSubDomainServer(testCase)
	server := httptest.NewServer(goSlowServer)
	defer server.Close()
	defer goSlowServer.storage.db.Close()
	checkFunc(t, server, testCase)
}

func checkZeroSite(t *testing.T, server *httptest.Server, testCase *TestCase) {
	bytesShouldBeEqual(t,
		readBody(GET(server.URL, "/", makeHost("0", TEST_ENDPOINT))),
		DEFAULT_BODY)
}

func TestTooLargeDelay(t *testing.T) {
	runAll(t, checkTooLargeDelay, defaultTestCases)
}

func checkTooLargeDelay(t *testing.T, server *httptest.Server, testCase *TestCase) {
	prefix := testCase.adminUrlPathPrefix
	domain := newDomain(server, join(prefix, "/booya"), []byte("haha"))
	site := getSite(domain)
	resp := addRule(server, &Rule{Site: site, Delay: time.Duration(1000) * time.Second})
	shouldHaveStatusCode(t, http.StatusBadRequest, resp)
	resp = GET(server.URL, "/", domain)
	shouldHaveStatusCode(t, http.StatusNotFound, resp)
}

func TestRedefineBuiltinSites(t *testing.T) {
	runAll(t, checkRedefineBuiltinSites, defaultTestCases)
}

func checkRedefineBuiltinSites(t *testing.T, server *httptest.Server, testCase *TestCase) {
	for _, site := range []string{"0", "99", "500", "create"} {
		resp := addRule(server, &Rule{Site: site, Path: "/test", Body: []byte("hop"), Method: "GET"})
		shouldHaveStatusCode(t, http.StatusForbidden, resp)
	}
}

func TestRedefineNonExistentSite(t *testing.T) {
	runAll(t, checkRedefineNonExistentSite, defaultTestCases)
}

func checkRedefineNonExistentSite(t *testing.T, server *httptest.Server, testCase *TestCase) {
	for _, site := range []string{"", "ha", "admin-500"} {
		resp := addRule(server, &Rule{Site: site})
		shouldHaveStatusCode(t, http.StatusNotFound, resp)
	}
}

func TestDelay(t *testing.T) {
	runAll(t, checkDelay, defaultTestCases)
}

func checkDelay(t *testing.T, server *httptest.Server, testCase *TestCase) {
	shouldRespondIn(t,
		createGET(server.URL, "/", makeHost("0", TEST_ENDPOINT)),
		0, 0.1) // seconds
	shouldRespondIn(t,
		createGET(server.URL, "/", makeHost("1", TEST_ENDPOINT)),
		1, 1.1) // seconds
}

func TestStatus(t *testing.T) {
	runAll(t, checkStatus, defaultTestCases)
}

func checkStatus(t *testing.T, server *httptest.Server, testCase *TestCase) {
	for _, statusCode := range []int{200, 404, 500} {
		resp := GET(server.URL, "/", makeHost(strconv.Itoa(statusCode), TEST_ENDPOINT))
		shouldHaveStatusCode(t, statusCode, resp)
	}
}

func TestRuleCreation(t *testing.T) {
	runAll(t, checkRuleCreationTestCase, ruleCreationTestCases)
}

// TODO: refactor
func checkRuleCreationTestCase(t *testing.T, server *httptest.Server, testCase *TestCase) {
	prefix := testCase.adminUrlPathPrefix
	domain, site := TEST_ENDPOINT, ""
	root_resp := []byte("haha")
	test_resp := []byte("hop")
	test_post_resp := []byte("for POST")
	empty_payload := []byte("")
	if prefix == "" {
		domain = newDomain(server, join(prefix, "/"), root_resp)
		site = getSite(domain)
	} else {
		resp := addRule(server, &Rule{Path: join(prefix, "/"), Body: root_resp})
		shouldHaveStatusCode(t, http.StatusOK, resp)
	}
	bytesShouldBeEqual(t, readBody(GET(server.URL, "/", domain)), root_resp)
	resp := addRule(server, &Rule{Site: site, Path: join(prefix, "/test"), Body: test_resp, Method: "GET"})
	shouldHaveStatusCode(t, http.StatusOK, resp)

	bytesShouldBeEqual(t, readBody(GET(server.URL, "/test", domain)), test_resp)
	resp = POST(server.URL, "/test", domain, []byte(""))
	intShouldBeEqual(t, 404, resp.StatusCode)
	resp = addRule(server, &Rule{Site: site, Path: join(prefix, "/test"), Body: test_post_resp, Method: "POST",
		Delay: time.Duration(100) * time.Millisecond})
	shouldHaveStatusCode(t, http.StatusOK, resp)
	bytesShouldBeEqual(t, readBody(GET(server.URL, "/test", domain)), test_resp)
	bytesShouldBeEqual(t, readBody(POST(server.URL, "/test", domain, []byte(""))), test_post_resp)
	shouldRespondIn(t, createPOST(server.URL, "/test", domain, empty_payload), 0.1, 0.15)
}

func newSubDomainServer(testCase *TestCase) *Server {
	config := DEFAULT_CONFIG // copies DEFAULT_CONFIG
	config.endpoint = TEST_ENDPOINT
	config.createDefaultRules = testCase.createDefaultRules
	config.adminUrlPathPrefix = testCase.adminUrlPathPrefix
	config.driver = testCase.driver
	config.dataSource = testCase.dataSource
	return NewServer(&config)
}

func GET(url, path, host string) *http.Response {
	req := createGET(url, path, host)
	return do(req)
}

func do(req *http.Request) *http.Response {
	resp, err := new(http.Client).Do(req)
	if err != nil {
		log.Fatal(err)
	}
	return resp
}

func createGET(url, path, host string) *http.Request {
	req, err := http.NewRequest("GET", url+path, nil)
	if err != nil {
		log.Fatal(err)
	}
	req.Host = host
	return req
}

func readBody(resp *http.Response) []byte {
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatal(err)
	}
	return body
}

func makeHost(subdomain, host string) string {
	return fmt.Sprintf("%s.%s", subdomain, host)
}

func bytesShouldBeEqual(t *testing.T, expected, actual []byte) {
	if !bytes.Equal(expected, actual) {
		t.Fatalf("<<%v>> != <<%v>>", string(expected), string(actual))
	}
}

func intShouldBeEqual(t *testing.T, expected, actual int) {
	if expected != actual {
		t.Fatalf("<<%v>> != <<%v>>", expected, actual)
	}
}

func shouldRespondIn(t *testing.T, req *http.Request, minSeconds, maxSeconds float64) {
	start := time.Now()
	resp := do(req)
	readBody(resp)
	duration := time.Since(start)
	minDuration := toDuration(minSeconds)
	maxDuration := toDuration(maxSeconds)
	if duration < minDuration || duration > maxDuration {
		t.Fatalf("%s%s answered in %v. Not in the interval [%v; %v]",
			req.Host, req.URL.Path, duration, minDuration, maxDuration)
	}
}

func shouldHaveStatusCode(t *testing.T, statusCode int, resp *http.Response) {
	intShouldBeEqual(t, statusCode, resp.StatusCode)
}

func toDuration(seconds float64) time.Duration {
	return time.Duration(seconds*1000) * time.Millisecond
}

func newDomain(server *httptest.Server, path string, response []byte) string {
	resp := POST(server.URL, fmt.Sprintf("%s?output=short&method=GET", path),
		makeHost("create", TEST_ENDPOINT), response)
	return string(readBody(resp))
}

func POST(url, path, host string, payload []byte) *http.Response {
	req := createPOST(url, path, host, payload)
	return do(req)
}

func createPOST(url, path, host string, payload []byte) *http.Request {
	req, err := http.NewRequest("POST", url+path, bytes.NewReader(payload))
	if err != nil {
		log.Fatal(err)
	}
	req.Host = host
	return req
}

func getSite(domain string) string {
	return strings.Split(domain, ".")[0]
}

// TODO: use normal GET-parameters builder, not Sprintf and string concatenation
func addRule(server *httptest.Server, rule *Rule) *http.Response {
	path := rule.Path
	path += "?method=" + rule.Method
	path += fmt.Sprintf("&delay=%f", rule.Delay.Seconds())
	return POST(server.URL, path, makeHost("admin-"+rule.Site, TEST_ENDPOINT),
		rule.Body)
}

// Wrapper around path.Join. Preserves trailing slash.
func join(elem ...string) string {
	lastElem := elem[len(elem)-1]
	shouldEndWithSlash := strings.HasSuffix(lastElem, "/")
	joined := path.Join(elem...)
	if shouldEndWithSlash && !strings.HasSuffix(joined, "/") {
		joined += "/"
	}
	return joined
}

func createDb(name string) {
	cmd := exec.Command("createdb", name)
	err := cmd.Run()
	if err != nil {
		log.Fatalf("createdb error: %s", err)
	}
}

func dropDb(name string) {
	cmd := exec.Command("dropdb", name)
	err := cmd.Run()
	if err != nil {
		log.Fatalf("dropdb error: %s", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/labstack/echo"
	"github.com/stretchr/testify/assert"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"path"
	"testing"
)

func TestGet(t *testing.T) {
	// Setup
	conf := Configuration{
		Server: struct {
			Port int
		}{
			1234,
		},
		Storage: struct {
			Directory string
		}{
			"testdata",
		},
	}
	body, _ := os.Open(path.Join(conf.Storage.Directory, "e3158990bdee63f8594c260cd51a011d"))
	data, _ := ioutil.ReadAll(body)

	e := echo.New()
	req := httptest.NewRequest(echo.GET, "/", body)
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec)
	c.SetPath("/users/:id")
	c.SetParamNames("id")
	c.SetParamValues("e3158990bdee63f8594c260cd51a011d")
	cc := &CustomContext{c, conf}

	// Assertions
	if assert.NoError(t, get(cc)) {
		assert.Equal(t, http.StatusOK, rec.Code)
		assert.Equal(t, data, rec.Body.Bytes())
	}
}
<commit_msg>Fix TestGet request body<commit_after>package main

import (
	"github.com/labstack/echo"
	"github.com/stretchr/testify/assert"
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"os"
	"path"
	"testing"
)

func TestGet(t *testing.T) {
	// Setup
	conf := Configuration{
		Server: struct {
			Port int
		}{
			1234,
		},
		Storage: struct {
			Directory string
		}{
			"testdata",
		},
	}
	body, _ := os.Open(path.Join(conf.Storage.Directory, "e3158990bdee63f8594c260cd51a011d"))
	data, _ := ioutil.ReadAll(body)

	e := echo.New()
	req := httptest.NewRequest(echo.GET, "/", nil)
	rec := httptest.NewRecorder()
	c := e.NewContext(req, rec)
	c.SetPath("/users/:id")
	c.SetParamNames("id")
	c.SetParamValues("e3158990bdee63f8594c260cd51a011d")
	cc := &CustomContext{c, conf}

	// Assertions
	if assert.NoError(t, get(cc)) {
		assert.Equal(t, http.StatusOK, rec.Code)
		assert.Equal(t, data, rec.Body.Bytes())
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 The gorest 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 gorest

import (
	"bytes"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestServer(t *testing.T) {
	checks := []struct {
		path   string
		method string
		want   []byte
	}{
		{"/h1", "GET", []byte("h1")},
		{"/h1", "POST", []byte("h1")},
		{"/h1", "PUT", []byte("h2")},
		{"/h2", "GET", []byte("h2")},
	}

	h1 := func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("h1"))
	}
	h2 := func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("h2"))
	}

	s := NewServer("")
	s.Route("/h1", http.HandlerFunc(h1)).Methods("GET", "POST")
	s.RouteDefault(http.HandlerFunc(h2))
	ts := httptest.NewServer(s.mux)

	for _, check := range checks {
		urlStr := ts.URL + check.path
		client := &http.Client{}
		req, err := http.NewRequest(check.method, urlStr, nil)
		if err != nil {
			log.Fatal(err)
		}
		resp, err := client.Do(req)
		if err != nil {
			log.Fatal(err)
		}
		defer resp.Body.Close()
		result, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Fatal(err)
		}
		if !bytes.Equal(result, check.want) {
			t.Errorf("Server(%s, %s)=%s; want=%s",
				check.path, check.method, result, check.want)
		}
	}
}
<commit_msg>Add more test cases to server_test.go<commit_after>// Copyright 2014 The gorest 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 gorest

import (
	"bytes"
	"io/ioutil"
	"log"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestServer(t *testing.T) {
	checks := []struct {
		path   string
		method string
		want   []byte
	}{
		{"/h1", "GET", []byte("h1")},
		{"/h1", "POST", []byte("h1")},
		{"/h1", "PUT", []byte("h3")},
		{"/h2", "GET", []byte("h2")},
		{"/h2", "POST", []byte("h2")},
		{"/h2", "PUT", []byte("h2")},
		{"/unk", "GET", []byte("h3")},
	}

	h1 := func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("h1"))
	}
	h2 := func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("h2"))
	}
	h3 := func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("h3"))
	}

	s := NewServer("")
	s.Route("/h1", http.HandlerFunc(h1)).Methods("GET", "POST")
	s.Route("/h2", http.HandlerFunc(h2))
	s.RouteDefault(http.HandlerFunc(h3))
	ts := httptest.NewServer(s.mux)

	for _, check := range checks {
		urlStr := ts.URL + check.path
		client := &http.Client{}
		req, err := http.NewRequest(check.method, urlStr, nil)
		if err != nil {
			log.Fatal(err)
		}
		resp, err := client.Do(req)
		if err != nil {
			log.Fatal(err)
		}
		defer resp.Body.Close()
		result, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			log.Fatal(err)
		}
		if !bytes.Equal(result, check.want) {
			t.Errorf("Server(%s, %s)=%s; want=%s",
				check.path, check.method, result, check.want)
		}
	}
}
<|endoftext|>


<commit_before>package testsrv

import (
	"net/http"
	"sync"
	"testing"
	"time"

	"github.com/arschles/assert"
)

const (
	recvWaitTime = 10 * time.Millisecond
)

func TestNoMsgs(t *testing.T) {
	srv := StartServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
	}))
	defer srv.Close()
	recvCh := make(chan []*ReceivedRequest)
	// ensure that it returns after waitTime
	go func() {
		recvCh <- srv.AcceptN(20, recvWaitTime/2)
	}()
	select {
	case recv := <-recvCh:
		assert.Equal(t, len(recv), 0, "number of received messages")
	case <-time.After(recvWaitTime):
		t.Errorf("AcceptN didn't return after [%+v]", recvWaitTime)
	}
}

func TestMsgs(t *testing.T) {
	const numSends = 20
	srv := StartServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	}))
	defer srv.Close()
	ch := make(chan []*ReceivedRequest)
	waitTime := 10 * time.Millisecond

	for i := 0; i < numSends; i++ {
		resp, err := http.Get(srv.URLStr())
		assert.NoErr(t, err)
		assert.Equal(t, http.StatusOK, resp.StatusCode, "status code")
	}

	go func() {
		ch <- srv.AcceptN(numSends, waitTime)
	}()
	select {
	case r := <-ch:
		assert.Equal(t, len(r), numSends, "number of recevied messages")
	case <-time.After(recvWaitTime):
		t.Errorf("AcceptN didn't return after [%+v]", recvWaitTime)
	}
}

func TestConcurrentClose(t *testing.T) {
	srv := StartServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
	defer srv.Close()
	var wg sync.WaitGroup
	for i := 0; i < 100; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			srv.Close()
		}()
	}
	wg.Wait()
}

func TestConcurrentSend(t *testing.T) {
	const numSends = 100
	srv := StartServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	}))
	defer srv.Close()
	var wg sync.WaitGroup
	for i := 0; i < numSends; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			resp, err := http.Get(srv.URLStr())
			if err != nil {
				t.Errorf("error on GET [%s]", err)
				return
			}
			if resp.StatusCode != http.StatusOK {
				t.Errorf("expected code [%d] got [%d]", http.StatusOK, resp.StatusCode)
				return
			}
		}()
	}
	wg.Wait()
	recv := srv.AcceptN(numSends, 10*time.Millisecond)
	assert.Equal(t, numSends, len(recv), "number of received requests")
}

func TestHandlerSleep(t *testing.T) {
	const numSends = 10
	ch := make(chan struct{})
	srv := StartServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		w.(http.Flusher).Flush()
		<-ch
	}))
	defer srv.Close()
	defer close(ch)

	var wg sync.WaitGroup
	for i := 0; i < numSends; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			resp, err := http.Get(srv.URLStr())
			if err != nil {
				t.Errorf("got error on GET when not expected [%s]", err)
				return
			}
			if resp.StatusCode != http.StatusOK {
				t.Errorf("got status [%d] expected [%d]", resp.StatusCode, http.StatusOK)
				return
			}
		}()
	}
	wgChan := make(chan struct{})
	go func() {
		wg.Wait()
		close(wgChan)
	}()
	select {
	case <-wgChan:
	case <-time.After(100 * time.Millisecond):
		t.Fatalf("not all senders completed within 100ms")
	}
	recv := srv.AcceptN(numSends, 10*time.Millisecond)
	assert.Equal(t, 0, len(recv), "num received messages")
}

func TestConcurrenctClose(t *testing.T) {
	srv := StartServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}))
	var wg sync.WaitGroup
	for i := 0; i < 100; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			srv.Close()
		}()
	}
	wg.Wait()
}
<commit_msg>fail a test to see what happens!<commit_after>package testsrv

import (
	"net/http"
	"sync"
	"testing"
	"time"

	"github.com/arschles/assert"
)

const (
	recvWaitTime = 10 * time.Millisecond
)

func TestNoMsgs(t *testing.T) {
	srv := StartServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(200)
	}))
	defer srv.Close()
	recvCh := make(chan []*ReceivedRequest)
	// ensure that it returns after waitTime
	go func() {
		recvCh <- srv.AcceptN(20, recvWaitTime/2)
	}()
	select {
	case recv := <-recvCh:
		assert.Equal(t, len(recv), 0, "number of received messages")
	case <-time.After(recvWaitTime):
		t.Errorf("AcceptN didn't return after [%+v]", recvWaitTime)
	}
	t.Fatalf("let's see what happens when we fail a test in Azure pipelines!")
}

func TestMsgs(t *testing.T) {
	const numSends = 20
	srv := StartServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	}))
	defer srv.Close()
	ch := make(chan []*ReceivedRequest)
	waitTime := 10 * time.Millisecond

	for i := 0; i < numSends; i++ {
		resp, err := http.Get(srv.URLStr())
		assert.NoErr(t, err)
		assert.Equal(t, http.StatusOK, resp.StatusCode, "status code")
	}

	go func() {
		ch <- srv.AcceptN(numSends, waitTime)
	}()
	select {
	case r := <-ch:
		assert.Equal(t, len(r), numSends, "number of recevied messages")
	case <-time.After(recvWaitTime):
		t.Errorf("AcceptN didn't return after [%+v]", recvWaitTime)
	}
}

func TestConcurrentClose(t *testing.T) {
	srv := StartServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
	defer srv.Close()
	var wg sync.WaitGroup
	for i := 0; i < 100; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			srv.Close()
		}()
	}
	wg.Wait()
}

func TestConcurrentSend(t *testing.T) {
	const numSends = 100
	srv := StartServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
	}))
	defer srv.Close()
	var wg sync.WaitGroup
	for i := 0; i < numSends; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			resp, err := http.Get(srv.URLStr())
			if err != nil {
				t.Errorf("error on GET [%s]", err)
				return
			}
			if resp.StatusCode != http.StatusOK {
				t.Errorf("expected code [%d] got [%d]", http.StatusOK, resp.StatusCode)
				return
			}
		}()
	}
	wg.Wait()
	recv := srv.AcceptN(numSends, 10*time.Millisecond)
	assert.Equal(t, numSends, len(recv), "number of received requests")
}

func TestHandlerSleep(t *testing.T) {
	const numSends = 10
	ch := make(chan struct{})
	srv := StartServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		w.(http.Flusher).Flush()
		<-ch
	}))
	defer srv.Close()
	defer close(ch)

	var wg sync.WaitGroup
	for i := 0; i < numSends; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			resp, err := http.Get(srv.URLStr())
			if err != nil {
				t.Errorf("got error on GET when not expected [%s]", err)
				return
			}
			if resp.StatusCode != http.StatusOK {
				t.Errorf("got status [%d] expected [%d]", resp.StatusCode, http.StatusOK)
				return
			}
		}()
	}
	wgChan := make(chan struct{})
	go func() {
		wg.Wait()
		close(wgChan)
	}()
	select {
	case <-wgChan:
	case <-time.After(100 * time.Millisecond):
		t.Fatalf("not all senders completed within 100ms")
	}
	recv := srv.AcceptN(numSends, 10*time.Millisecond)
	assert.Equal(t, 0, len(recv), "num received messages")
}

func TestConcurrenctClose(t *testing.T) {
	srv := StartServer(http.HandlerFunc(func(http.ResponseWriter, *http.Request) {}))
	var wg sync.WaitGroup
	for i := 0; i < 100; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			srv.Close()
		}()
	}
	wg.Wait()
}
<|endoftext|>


<commit_before>/*
Package shellescape provides the shellescape.Quote to escape arbitrary
strings for a safe use as command line arguments in the most common
POSIX shells.

The original Python package which this work was inspired by can be found
at https://pypi.python.org/pypi/shellescape.
*/
package shellescape

/*
The functionality provided by shellescape.Quote could be helpful
in those cases where it is known that the output of a Go program will
be appended to/used in the context of shell programs' command line arguments.
*/

import (
	"regexp"
	"strings"
)

var pattern *regexp.Regexp

func init() {
	pattern = regexp.MustCompilePOSIX("[^a-zA-Z0-9_^@%+=:,./-]")
}

// Quote returns a shell-escaped version of the string s. The returned value
// is a string that can safely be used as one token in a shell command line.
func Quote(s string) string {
	if len(s) == 0 {
		return "''"
	}
	if pattern.MatchString(s) {
		return "'" + strings.Replace(s, "'", "'\"'\"'", -1) + "'"
	}

	return s
}
<commit_msg>Use same _find_unsafe regexp from cpython: https://github.com/python/cpython/blob/master/Lib/shlex.py#L308-L319<commit_after>/*
Package shellescape provides the shellescape.Quote to escape arbitrary
strings for a safe use as command line arguments in the most common
POSIX shells.

The original Python package which this work was inspired by can be found
at https://pypi.python.org/pypi/shellescape.
*/
package shellescape

/*
The functionality provided by shellescape.Quote could be helpful
in those cases where it is known that the output of a Go program will
be appended to/used in the context of shell programs' command line arguments.
*/

import (
	"regexp"
	"strings"
)

var pattern *regexp.Regexp

func init() {
	pattern = regexp.MustCompile(`[^\w@%+=:,./-]`)
}

// Quote returns a shell-escaped version of the string s. The returned value
// is a string that can safely be used as one token in a shell command line.
func Quote(s string) string {
	if len(s) == 0 {
		return "''"
	}
	if pattern.MatchString(s) {
		return "'" + strings.Replace(s, "'", "'\"'\"'", -1) + "'"
	}

	return s
}
<|endoftext|>


<commit_before>package lattice

import (
	"fmt"
	"io"
	"strings"
	"sync"
	"unicode"
	"unicode/utf8"

	"github.com/ikawaha/kagome-dict/dict"
)

const (
	maximumCost              = 1<<31 - 1
	maximumUnknownWordLength = 1024
	searchModeKanjiLength    = 2
	searchModeKanjiPenalty   = 3000
	searchModeOtherLength    = 7
	searchModeOtherPenalty   = 1700
)

// TokenizeMode represents how to tokenize sentence.
type TokenizeMode int

const (
	// Normal Mode
	Normal TokenizeMode = iota + 1
	// Search Mode
	Search
	// Extended Mode
	Extended
)

var latticePool = sync.Pool{
	New: func() interface{} {
		return new(Lattice)
	},
}

// Lattice represents a grid of morph nodes.
type Lattice struct {
	Input  string
	Output []*node
	list   [][]*node
	dic    *dict.Dict
	udic   *dict.UserDict
}

// New returns a new lattice.
func New(d *dict.Dict, u *dict.UserDict) *Lattice {
	la := latticePool.Get().(*Lattice)
	la.dic = d
	la.udic = u
	return la
}

// Free releases a memory of a lattice.
func (la *Lattice) Free() {
	la.Input = ""
	for i := range la.Output {
		la.Output[i] = nil
	}
	la.Output = la.Output[:0]
	for i := range la.list {
		for j := range la.list[i] {
			nodePool.Put(la.list[i][j])
			la.list[i][j] = nil
		}
		la.list[i] = la.list[i][:0]
	}
	la.list = la.list[:0]
	la.udic = nil
	latticePool.Put(la)
}

func (la *Lattice) addNode(pos, id, position, start int, class NodeClass, surface string) {
	var m dict.Morph
	switch class {
	case DUMMY:
		// use default cost
	case KNOWN:
		m = la.dic.Morphs[id]
	case UNKNOWN:
		m = la.dic.UnkDict.Morphs[id]
	case USER:
		// use default cost
	}
	n := newNode()
	n.ID = id
	n.Position = position
	n.Start = start
	n.Class = class
	n.Cost = 0
	n.Left, n.Right, n.Weight = int32(m.LeftID), int32(m.RightID), int32(m.Weight)
	n.Surface = surface
	n.Prev = nil
	p := pos + utf8.RuneCountInString(surface)
	la.list[p] = append(la.list[p], n)
}

// Build builds a lattice from the inputs.
func (la *Lattice) Build(inp string) {
	rc := utf8.RuneCountInString(inp)
	la.Input = inp
	if cap(la.list) < rc+2 {
		const expandRatio = 2
		la.list = make([][]*node, 0, (rc+2)*expandRatio)
	}
	la.list = la.list[0 : rc+2]

	la.addNode(0, BosEosID, 0, 0, DUMMY, inp[0:0])
	la.addNode(rc+1, BosEosID, len(inp), rc, DUMMY, inp[rc:rc])

	runePos := -1
	for pos, ch := range inp {
		runePos++
		anyMatches := false

		// (1) USER DIC
		if la.udic != nil {
			la.udic.Index.CommonPrefixSearchCallback(inp[pos:], func(id, l int) {
				la.addNode(runePos, id, pos, runePos, USER, inp[pos:pos+l])
				if !anyMatches {
					anyMatches = true
				}
			})
		}
		if anyMatches {
			continue
		}
		// (2) KNOWN DIC
		la.dic.Index.CommonPrefixSearchCallback(inp[pos:], func(id, l int) {
			la.addNode(runePos, id, pos, runePos, KNOWN, inp[pos:pos+l])
			if !anyMatches {
				anyMatches = true
			}
		})
		// (3) UNKNOWN DIC
		class := la.dic.CharacterCategory(ch)
		if !anyMatches || la.dic.InvokeList[int(class)] {
			var endPos int
			if ch != utf8.RuneError {
				endPos = pos + utf8.RuneLen(ch)
			} else {
				endPos = pos + 1
			}
			unkWordLen := 1
			if la.dic.GroupList[int(class)] {
				for i, w, size := endPos, 0, len(inp); i < size; i += w {
					var c rune
					c, w = utf8.DecodeRuneInString(inp[i:])
					if la.dic.CharacterCategory(c) != class {
						break
					}
					endPos += w
					unkWordLen++
					if unkWordLen >= maximumUnknownWordLength {
						break
					}
				}
			}
			id := la.dic.UnkDict.Index[int32(class)]
			for i, w := pos, 0; i < endPos; i += w {
				_, w = utf8.DecodeRuneInString(inp[i:])
				end := i + w
				dup := la.dic.UnkDict.IndexDup[int32(class)]
				for x := 0; x < int(dup)+1; x++ {
					la.addNode(runePos, int(id)+x, pos, runePos, UNKNOWN, inp[pos:end])
				}
			}
		}
	}
}

// String returns a debug string of a lattice.
func (la *Lattice) String() string {
	str := ""
	for i, nodes := range la.list {
		str += fmt.Sprintf("[%v] :\n", i)
		for _, node := range nodes {
			str += fmt.Sprintf("%v\n", node)
		}
		str += "\n"
	}
	return str
}

func kanjiOnly(s string) bool {
	for _, r := range s {
		if !unicode.In(r, unicode.Ideographic) {
			return false
		}
	}
	return s != ""
}

func additionalCost(n *node) int {
	l := utf8.RuneCountInString(n.Surface)
	if l > searchModeKanjiLength && kanjiOnly(n.Surface) {
		return (l - searchModeKanjiLength) * searchModeKanjiPenalty
	}
	if l > searchModeOtherLength {
		return (l - searchModeOtherLength) * searchModeOtherPenalty
	}
	return 0
}

// Forward runs forward algorithm of the Viterbi.
func (la *Lattice) Forward(m TokenizeMode) {
	for i, size := 1, len(la.list); i < size; i++ {
		currentList := la.list[i]
		for index, target := range currentList {
			prevList := la.list[target.Start]
			if len(prevList) == 0 {
				la.list[i][index].Cost = maximumCost
				continue
			}
			for j, n := range prevList {
				var c int16
				if n.Class != USER && target.Class != USER {
					c = la.dic.Connection.At(int(n.Right), int(target.Left))
				}
				totalCost := int64(c) + int64(target.Weight) + int64(n.Cost)
				if m != Normal {
					totalCost += int64(additionalCost(n))
				}
				if totalCost > maximumCost {
					totalCost = maximumCost
				}
				if j == 0 || int32(totalCost) < la.list[i][index].Cost {
					la.list[i][index].Cost = int32(totalCost)
					la.list[i][index].Prev = la.list[target.Start][j]
				}
			}
		}
	}
}

// Backward runs backward algorithm of the Viterbi.
func (la *Lattice) Backward(m TokenizeMode) {
	const bufferExpandRatio = 2
	size := len(la.list)
	if size == 0 {
		return
	}
	if cap(la.Output) < size {
		la.Output = make([]*node, 0, size*bufferExpandRatio)
	} else {
		la.Output = la.Output[:0]
	}
	for p := la.list[size-1][0]; p != nil; p = p.Prev {
		if m != Extended || p.Class != UNKNOWN {
			la.Output = append(la.Output, p)
			continue
		}
		runeLen := utf8.RuneCountInString(p.Surface)
		stack := make([]*node, 0, runeLen)
		i := 0
		for _, r := range p.Surface {
			stack = append(stack, &node{
				ID:      p.ID,
				Start:   p.Start + i,
				Class:   DUMMY,
				Surface: string(r),
			})
			i++
		}
		for j, end := 0, len(stack); j < end; j++ {
			la.Output = append(la.Output, stack[runeLen-1-j])
		}
	}
}

func features(dict *dict.Dict, udict *dict.UserDict, n *node) []string {
	switch n.Class {
	case DUMMY:
		return nil
	case KNOWN:
		var c int
		if dict.Contents != nil {
			c = len(dict.Contents[n.ID])
		}
		features := make([]string, 0, len(dict.POSTable.POSs[n.ID])+c)
		for _, id := range dict.POSTable.POSs[n.ID] {
			features = append(features, dict.POSTable.NameList[id])
		}
		if dict.Contents != nil {
			features = append(features, dict.Contents[n.ID]...)
		}
		return features
	case UNKNOWN:
		features := make([]string, len(dict.UnkDict.Contents[n.ID]))
		for i := range dict.UnkDict.Contents[n.ID] {
			features[i] = dict.UnkDict.Contents[n.ID][i]
		}
		return features
	case USER:
		pos := udict.Contents[n.ID].Pos
		tokens := strings.Join(udict.Contents[n.ID].Tokens, "/")
		yomi := strings.Join(udict.Contents[n.ID].Yomi, "/")
		return []string{pos, tokens, yomi}
	}
	return nil
}

// Dot outputs the lattice in the graphviz dot format.
func (la *Lattice) Dot(w io.Writer) {
	bests := make(map[*node]struct{})
	for _, n := range la.Output {
		bests[n] = struct{}{}
	}
	type edge struct {
		from *node
		to   *node
	}
	edges := make([]edge, 0, 1024)
	for i, size := 1, len(la.list); i < size; i++ {
		currents := la.list[i]
		for _, to := range currents {
			if to.Class == UNKNOWN {
				if _, ok := bests[to]; !ok {
					continue
				}
			}
			prevs := la.list[to.Start]
			if len(prevs) == 0 {
				continue
			}
			for _, from := range prevs {
				if from.Class == UNKNOWN {
					if _, ok := bests[from]; !ok {
						continue
					}
				}
				edges = append(edges, edge{from, to})
			}
		}
	}
	fmt.Fprintln(w, "graph lattice {")
	fmt.Fprintln(w, "dpi=48;")
	fmt.Fprintln(w, "graph [style=filled, splines=true, overlap=false, fontsize=30, rankdir=LR]")
	fmt.Fprintln(w, "edge [fontname=Helvetica, fontcolor=red, color=\"#606060\"]")
	fmt.Fprintln(w, "node [shape=box, style=filled, fillcolor=\"#e8e8f0\", fontname=Helvetica]")
	for i, list := range la.list {
		for _, n := range list {
			if n.Class == UNKNOWN {
				if _, ok := bests[n]; !ok {
					continue
				}
			}
			surf := n.Surface
			if n.ID == BosEosID {
				if i == 0 {
					surf = "BOS"
				} else {
					surf = "EOS"
				}
			}
			features := features(la.dic, la.udic, n)
			pos := "---"
			if len(features) > 1 {
				pos = features[0]
			}
			if _, ok := bests[n]; ok {
				fmt.Fprintf(w, "\t\"%p\" [label=\"%s\\n%s\\n%d\",shape=ellipse, peripheries=2];\n", n, surf, pos, n.Weight)
			} else if n.Class != UNKNOWN {
				fmt.Fprintf(w, "\t\"%p\" [label=\"%s\\n%s\\n%d\"];\n", n, surf, pos, n.Weight)
			}
		}
	}
	for _, e := range edges {
		var c int16
		if e.from.Class != USER && e.to.Class != USER {
			c = la.dic.Connection.At(int(e.from.Right), int(e.to.Left))
		}
		_, l := bests[e.from]
		_, r := bests[e.to]
		if l && r {
			fmt.Fprintf(w, "\t\"%p\" -- \"%p\" [label=\"%d\", style=bold, color=blue, fontcolor=blue];\n",
				e.from, e.to, c)
		} else {
			fmt.Fprintf(w, "\t\"%p\" -- \"%p\" [label=\"%d\"];\n",
				e.from, e.to, c)
		}
	}

	fmt.Fprintln(w, "}")
}
<commit_msg>Add nolint gocyclo (#203)<commit_after>package lattice

import (
	"fmt"
	"io"
	"strings"
	"sync"
	"unicode"
	"unicode/utf8"

	"github.com/ikawaha/kagome-dict/dict"
)

const (
	maximumCost              = 1<<31 - 1
	maximumUnknownWordLength = 1024
	searchModeKanjiLength    = 2
	searchModeKanjiPenalty   = 3000
	searchModeOtherLength    = 7
	searchModeOtherPenalty   = 1700
)

// TokenizeMode represents how to tokenize sentence.
type TokenizeMode int

const (
	// Normal Mode
	Normal TokenizeMode = iota + 1
	// Search Mode
	Search
	// Extended Mode
	Extended
)

var latticePool = sync.Pool{
	New: func() interface{} {
		return new(Lattice)
	},
}

// Lattice represents a grid of morph nodes.
type Lattice struct {
	Input  string
	Output []*node
	list   [][]*node
	dic    *dict.Dict
	udic   *dict.UserDict
}

// New returns a new lattice.
func New(d *dict.Dict, u *dict.UserDict) *Lattice {
	la := latticePool.Get().(*Lattice)
	la.dic = d
	la.udic = u
	return la
}

// Free releases a memory of a lattice.
func (la *Lattice) Free() {
	la.Input = ""
	for i := range la.Output {
		la.Output[i] = nil
	}
	la.Output = la.Output[:0]
	for i := range la.list {
		for j := range la.list[i] {
			nodePool.Put(la.list[i][j])
			la.list[i][j] = nil
		}
		la.list[i] = la.list[i][:0]
	}
	la.list = la.list[:0]
	la.udic = nil
	latticePool.Put(la)
}

func (la *Lattice) addNode(pos, id, position, start int, class NodeClass, surface string) {
	var m dict.Morph
	switch class {
	case DUMMY:
		// use default cost
	case KNOWN:
		m = la.dic.Morphs[id]
	case UNKNOWN:
		m = la.dic.UnkDict.Morphs[id]
	case USER:
		// use default cost
	}
	n := newNode()
	n.ID = id
	n.Position = position
	n.Start = start
	n.Class = class
	n.Cost = 0
	n.Left, n.Right, n.Weight = int32(m.LeftID), int32(m.RightID), int32(m.Weight)
	n.Surface = surface
	n.Prev = nil
	p := pos + utf8.RuneCountInString(surface)
	la.list[p] = append(la.list[p], n)
}

// Build builds a lattice from the inputs.
// nolint: gocyclo
func (la *Lattice) Build(inp string) {
	rc := utf8.RuneCountInString(inp)
	la.Input = inp
	if cap(la.list) < rc+2 {
		const expandRatio = 2
		la.list = make([][]*node, 0, (rc+2)*expandRatio)
	}
	la.list = la.list[0 : rc+2]

	la.addNode(0, BosEosID, 0, 0, DUMMY, inp[0:0])
	la.addNode(rc+1, BosEosID, len(inp), rc, DUMMY, inp[rc:rc])

	runePos := -1
	for pos, ch := range inp {
		runePos++
		anyMatches := false

		// (1) USER DIC
		if la.udic != nil {
			la.udic.Index.CommonPrefixSearchCallback(inp[pos:], func(id, l int) {
				la.addNode(runePos, id, pos, runePos, USER, inp[pos:pos+l])
				if !anyMatches {
					anyMatches = true
				}
			})
		}
		if anyMatches {
			continue
		}
		// (2) KNOWN DIC
		la.dic.Index.CommonPrefixSearchCallback(inp[pos:], func(id, l int) {
			la.addNode(runePos, id, pos, runePos, KNOWN, inp[pos:pos+l])
			if !anyMatches {
				anyMatches = true
			}
		})
		// (3) UNKNOWN DIC
		class := la.dic.CharacterCategory(ch)
		if !anyMatches || la.dic.InvokeList[int(class)] {
			var endPos int
			if ch != utf8.RuneError {
				endPos = pos + utf8.RuneLen(ch)
			} else {
				endPos = pos + 1
			}
			unkWordLen := 1
			if la.dic.GroupList[int(class)] {
				for i, w, size := endPos, 0, len(inp); i < size; i += w {
					var c rune
					c, w = utf8.DecodeRuneInString(inp[i:])
					if la.dic.CharacterCategory(c) != class {
						break
					}
					endPos += w
					unkWordLen++
					if unkWordLen >= maximumUnknownWordLength {
						break
					}
				}
			}
			id := la.dic.UnkDict.Index[int32(class)]
			for i, w := pos, 0; i < endPos; i += w {
				_, w = utf8.DecodeRuneInString(inp[i:])
				end := i + w
				dup := la.dic.UnkDict.IndexDup[int32(class)]
				for x := 0; x < int(dup)+1; x++ {
					la.addNode(runePos, int(id)+x, pos, runePos, UNKNOWN, inp[pos:end])
				}
			}
		}
	}
}

// String returns a debug string of a lattice.
func (la *Lattice) String() string {
	str := ""
	for i, nodes := range la.list {
		str += fmt.Sprintf("[%v] :\n", i)
		for _, node := range nodes {
			str += fmt.Sprintf("%v\n", node)
		}
		str += "\n"
	}
	return str
}

func kanjiOnly(s string) bool {
	for _, r := range s {
		if !unicode.In(r, unicode.Ideographic) {
			return false
		}
	}
	return s != ""
}

func additionalCost(n *node) int {
	l := utf8.RuneCountInString(n.Surface)
	if l > searchModeKanjiLength && kanjiOnly(n.Surface) {
		return (l - searchModeKanjiLength) * searchModeKanjiPenalty
	}
	if l > searchModeOtherLength {
		return (l - searchModeOtherLength) * searchModeOtherPenalty
	}
	return 0
}

// Forward runs forward algorithm of the Viterbi.
func (la *Lattice) Forward(m TokenizeMode) {
	for i, size := 1, len(la.list); i < size; i++ {
		currentList := la.list[i]
		for index, target := range currentList {
			prevList := la.list[target.Start]
			if len(prevList) == 0 {
				la.list[i][index].Cost = maximumCost
				continue
			}
			for j, n := range prevList {
				var c int16
				if n.Class != USER && target.Class != USER {
					c = la.dic.Connection.At(int(n.Right), int(target.Left))
				}
				totalCost := int64(c) + int64(target.Weight) + int64(n.Cost)
				if m != Normal {
					totalCost += int64(additionalCost(n))
				}
				if totalCost > maximumCost {
					totalCost = maximumCost
				}
				if j == 0 || int32(totalCost) < la.list[i][index].Cost {
					la.list[i][index].Cost = int32(totalCost)
					la.list[i][index].Prev = la.list[target.Start][j]
				}
			}
		}
	}
}

// Backward runs backward algorithm of the Viterbi.
func (la *Lattice) Backward(m TokenizeMode) {
	const bufferExpandRatio = 2
	size := len(la.list)
	if size == 0 {
		return
	}
	if cap(la.Output) < size {
		la.Output = make([]*node, 0, size*bufferExpandRatio)
	} else {
		la.Output = la.Output[:0]
	}
	for p := la.list[size-1][0]; p != nil; p = p.Prev {
		if m != Extended || p.Class != UNKNOWN {
			la.Output = append(la.Output, p)
			continue
		}
		runeLen := utf8.RuneCountInString(p.Surface)
		stack := make([]*node, 0, runeLen)
		i := 0
		for _, r := range p.Surface {
			stack = append(stack, &node{
				ID:      p.ID,
				Start:   p.Start + i,
				Class:   DUMMY,
				Surface: string(r),
			})
			i++
		}
		for j, end := 0, len(stack); j < end; j++ {
			la.Output = append(la.Output, stack[runeLen-1-j])
		}
	}
}

func features(dict *dict.Dict, udict *dict.UserDict, n *node) []string {
	switch n.Class {
	case DUMMY:
		return nil
	case KNOWN:
		var c int
		if dict.Contents != nil {
			c = len(dict.Contents[n.ID])
		}
		features := make([]string, 0, len(dict.POSTable.POSs[n.ID])+c)
		for _, id := range dict.POSTable.POSs[n.ID] {
			features = append(features, dict.POSTable.NameList[id])
		}
		if dict.Contents != nil {
			features = append(features, dict.Contents[n.ID]...)
		}
		return features
	case UNKNOWN:
		features := make([]string, len(dict.UnkDict.Contents[n.ID]))
		for i := range dict.UnkDict.Contents[n.ID] {
			features[i] = dict.UnkDict.Contents[n.ID][i]
		}
		return features
	case USER:
		pos := udict.Contents[n.ID].Pos
		tokens := strings.Join(udict.Contents[n.ID].Tokens, "/")
		yomi := strings.Join(udict.Contents[n.ID].Yomi, "/")
		return []string{pos, tokens, yomi}
	}
	return nil
}

// Dot outputs the lattice in the graphviz dot format.
func (la *Lattice) Dot(w io.Writer) {
	bests := make(map[*node]struct{})
	for _, n := range la.Output {
		bests[n] = struct{}{}
	}
	type edge struct {
		from *node
		to   *node
	}
	edges := make([]edge, 0, 1024)
	for i, size := 1, len(la.list); i < size; i++ {
		currents := la.list[i]
		for _, to := range currents {
			if to.Class == UNKNOWN {
				if _, ok := bests[to]; !ok {
					continue
				}
			}
			prevs := la.list[to.Start]
			if len(prevs) == 0 {
				continue
			}
			for _, from := range prevs {
				if from.Class == UNKNOWN {
					if _, ok := bests[from]; !ok {
						continue
					}
				}
				edges = append(edges, edge{from, to})
			}
		}
	}
	fmt.Fprintln(w, "graph lattice {")
	fmt.Fprintln(w, "dpi=48;")
	fmt.Fprintln(w, "graph [style=filled, splines=true, overlap=false, fontsize=30, rankdir=LR]")
	fmt.Fprintln(w, "edge [fontname=Helvetica, fontcolor=red, color=\"#606060\"]")
	fmt.Fprintln(w, "node [shape=box, style=filled, fillcolor=\"#e8e8f0\", fontname=Helvetica]")
	for i, list := range la.list {
		for _, n := range list {
			if n.Class == UNKNOWN {
				if _, ok := bests[n]; !ok {
					continue
				}
			}
			surf := n.Surface
			if n.ID == BosEosID {
				if i == 0 {
					surf = "BOS"
				} else {
					surf = "EOS"
				}
			}
			features := features(la.dic, la.udic, n)
			pos := "---"
			if len(features) > 1 {
				pos = features[0]
			}
			if _, ok := bests[n]; ok {
				fmt.Fprintf(w, "\t\"%p\" [label=\"%s\\n%s\\n%d\",shape=ellipse, peripheries=2];\n", n, surf, pos, n.Weight)
			} else if n.Class != UNKNOWN {
				fmt.Fprintf(w, "\t\"%p\" [label=\"%s\\n%s\\n%d\"];\n", n, surf, pos, n.Weight)
			}
		}
	}
	for _, e := range edges {
		var c int16
		if e.from.Class != USER && e.to.Class != USER {
			c = la.dic.Connection.At(int(e.from.Right), int(e.to.Left))
		}
		_, l := bests[e.from]
		_, r := bests[e.to]
		if l && r {
			fmt.Fprintf(w, "\t\"%p\" -- \"%p\" [label=\"%d\", style=bold, color=blue, fontcolor=blue];\n",
				e.from, e.to, c)
		} else {
			fmt.Fprintf(w, "\t\"%p\" -- \"%p\" [label=\"%d\"];\n",
				e.from, e.to, c)
		}
	}

	fmt.Fprintln(w, "}")
}
<|endoftext|>