diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d897808cb01..90b11ba2871 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -224,6 +224,7 @@ Dockerfile @sourcegraph/distribution # Precise code intel /cmd/precise-code-intel/ @sourcegraph/code-intel +/cmd/precise-code-intel-api-server/ @sourcegraph/code-intel /cmd/precise-code-intel-bundle-manager/ @sourcegraph/code-intel /internal/lsif @sourcegraph/code-intel /internal/codeintel @sourcegraph/code-intel diff --git a/cmd/precise-code-intel-api-server/Dockerfile b/cmd/precise-code-intel-api-server/Dockerfile new file mode 100644 index 00000000000..223525fc954 --- /dev/null +++ b/cmd/precise-code-intel-api-server/Dockerfile @@ -0,0 +1,20 @@ +FROM sourcegraph/alpine:3.10@sha256:4d05cd5669726fc38823e92320659a6d1ef7879e62268adec5df658a0bacf65c + +ARG COMMIT_SHA="unknown" +ARG DATE="unknown" +ARG VERSION="unknown" + +LABEL org.opencontainers.image.revision=${COMMIT_SHA} +LABEL org.opencontainers.image.created=${DATE} +LABEL org.opencontainers.image.version=${VERSION} +LABEL com.sourcegraph.github.url=https://github.com/sourcegraph/sourcegraph/commit/${COMMIT_SHA} + +# hadolint ignore=DL3018 +RUN apk update && apk add --no-cache \ + tini + +COPY ./precise-code-intel-api-server /usr/local/bin/precise-code-intel-api-server + +EXPOSE 3186 +ENV GO111MODULES=on LANG=en_US.utf8 LOG_LEVEL=debug +ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/precise-code-intel-api-server"] diff --git a/cmd/precise-code-intel-api-server/build.sh b/cmd/precise-code-intel-api-server/build.sh new file mode 100755 index 00000000000..97a0785d7c6 --- /dev/null +++ b/cmd/precise-code-intel-api-server/build.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +# This script builds the precise-code-intel-api-server docker image. + +cd "$(dirname "${BASH_SOURCE[0]}")/../.." +set -eu + +OUTPUT=$(mktemp -d -t sgdockerbuild_XXXXXXX) +cleanup() { + rm -rf "$OUTPUT" +} +trap cleanup EXIT + +# Environment for building linux binaries +export GO111MODULE=on +export GOARCH=amd64 +export GOOS=linux + +echo "--- go build" +pkg="github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server" +go build -trimpath -ldflags "-X github.com/sourcegraph/sourcegraph/internal/version.version=$VERSION" -buildmode exe -tags dist -o "$OUTPUT/$(basename $pkg)" "$pkg" + +echo "--- docker build" +docker build -f cmd/precise-code-intel-api-server/Dockerfile -t "$IMAGE" "$OUTPUT" \ + --progress=plain \ + --build-arg COMMIT_SHA \ + --build-arg DATE \ + --build-arg VERSION diff --git a/cmd/precise-code-intel-api-server/env.go b/cmd/precise-code-intel-api-server/env.go new file mode 100644 index 00000000000..c1bb9153e67 --- /dev/null +++ b/cmd/precise-code-intel-api-server/env.go @@ -0,0 +1,32 @@ +package main + +import ( + "log" + "time" + + "github.com/sourcegraph/sourcegraph/internal/env" +) + +var ( + rawBundleManagerURL = env.Get("PRECISE_CODE_INTEL_BUNDLE_MANAGER_URL", "", "HTTP address for internal LSIF bundle manager server.") + rawJanitorInterval = env.Get("PRECISE_CODE_INTEL_JANITOR_INTERVAL", "1m", "Interval between cleanup runs.") +) + +// mustGet returns the non-empty version of the given raw value fatally logs on failure. +func mustGet(rawValue, name string) string { + if rawValue == "" { + log.Fatalf("invalid value %q for %s: no value supplied", rawValue, name) + } + + return rawValue +} + +// mustParseInterval returns the interval version of the given raw value fatally logs on failure. +func mustParseInterval(rawValue, name string) time.Duration { + d, err := time.ParseDuration(rawValue) + if err != nil { + log.Fatalf("invalid duration %q for %s: %s", rawValue, name, err) + } + + return d +} diff --git a/cmd/precise-code-intel-api-server/internal/api/api.go b/cmd/precise-code-intel-api-server/internal/api/api.go new file mode 100644 index 00000000000..06c4c81c3dd --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/api/api.go @@ -0,0 +1,44 @@ +package api + +import ( + "context" + "errors" + + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" +) + +// CodeIntelAPI is the main interface into precise code intelligence data. +type CodeIntelAPI interface { + // FindClosestDumps returns the set of dumps that can most accurately answer code intelligence + // queries for the given file. These dump IDs should be subsequently passed to invocations of + // Definitions, References, and Hover. + FindClosestDumps(ctx context.Context, repositoryID int, commit, file string) ([]db.Dump, error) + + // Definitions returns the list of source locations that define the symbol at the given position. + // This may include remote definitions if the remote repository is also indexed. + Definitions(ctx context.Context, file string, line, character, uploadID int) ([]ResolvedLocation, error) + + // References returns the list of source locations that reference the symbol at the given position. + // This may include references from other dumps and repositories. + References(ctx context.Context, repositoryID int, commit string, limit int, cursor Cursor) ([]ResolvedLocation, Cursor, bool, error) + + // Hover returns the hover text and range for the symbol at the given position. + Hover(ctx context.Context, file string, line, character, uploadID int) (string, bundles.Range, bool, error) +} + +type codeIntelAPI struct { + db db.DB + bundleManagerClient bundles.BundleManagerClient +} + +var _ CodeIntelAPI = &codeIntelAPI{} + +var ErrMissingDump = errors.New("no dump") + +func New(db db.DB, bundleManagerClient bundles.BundleManagerClient) CodeIntelAPI { + return &codeIntelAPI{ + db: db, + bundleManagerClient: bundleManagerClient, + } +} diff --git a/cmd/precise-code-intel-api-server/internal/api/bloom_filter.go b/cmd/precise-code-intel-api-server/internal/api/bloom_filter.go new file mode 100644 index 00000000000..399e2b73e12 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/api/bloom_filter.go @@ -0,0 +1,141 @@ +package api + +import ( + "bytes" + "compress/gzip" + "encoding/json" + "io/ioutil" + "math" + "unicode" + "unicode/utf16" +) + +// decodeAndTestFilter decodes the filter and determines if identifier is a member of the underlying +// set. Returns an error if the encoded filter is malformed (improperly compressed or invalid JSON). +func decodeAndTestFilter(encodedFilter []byte, identifier string) (bool, error) { + payload := struct { + Buckets []int `json:"buckets"` + NumHashFunctions int32 `json:"numHashFunctions"` + }{} + + r, err := gzip.NewReader(bytes.NewReader(encodedFilter)) + if err != nil { + return false, err + } + + f, err := ioutil.ReadAll(r) + if err != nil { + return false, err + } + + if err := json.Unmarshal(f, &payload); err != nil { + return false, err + } + + // + // TODO - document bloom filter behaviors + // + + locations := hashLocations( + identifier, + int32(math.Ceil(float64(len(payload.Buckets)))*32), + payload.NumHashFunctions, + ) + + for _, b := range locations { + if (payload.Buckets[int(math.Floor(float64(b)/32))] & (1 << (b % 32))) == 0 { + return false, nil + } + } + + return true, nil +} + +// The following code is a port of bloomfilter 0.0.18 from npm. We chose not to recreate all the bloom +// filters stored in Postgres because we want a transitionary period where both services (TS and Go) can +// exist and be behaviorally equivalent. +// +// There are not a large number of differences, but there are some subtle ones around overflow behavior +// and UTF-8/16 encoding. The accompanying test suite uses filters generated by the original TypeScript +// code to ensure that they can be read without a migration step. We may want to run a migration step to +// simplify this dependency, but it is in no way urgent. +// +// The original code available at https://github.com/jasondavies/bloomfilter.js. + +// Original notes: +// See http://willwhim.wpengine.com/2011/09/03/producing-n-hash-functions-by-hashing-only-once/. +func hashLocations(v string, m, k int32) []int32 { + a := fowlerNollVo1a(v, 0) + b := fowlerNollVo1a(v, 1576284489) // The seed value is chosen randomly + x := a % int32(m) + r := make([]int32, k) + + for i := int32(0); i < k; i++ { + if x < 0 { + r[i] = x + int32(m) + } else { + r[i] = x + } + x = (x + b) % int32(m) + } + + return r +} + +// Original notes: +// Fowler/Noll/Vo hashing. This function optionally takes a seed value that is incorporated +// into the offset basis. Almost any choice of offset basis will serve so long as it is non-zero, +// according to http://www.isthe.com/chongo/tech/comp/fnv/index.html. +func fowlerNollVo1a(v string, seed int32) int32 { + q := 2166136261 + a := int64(int32(q) ^ seed) + + for _, r := range utf16Runes(v) { + c := int64(r) + if d := c & 0xff00; d != 0 { + a = (fowlerNollVoMultiply(int32(a ^ int64(d>>8)))) + } + a = fowlerNollVoMultiply(int32(a) ^ int32(c&0xff)) + } + + return fowlerNollVoMix(int32(a)) +} + +// Original notes: +// Equivalent to `a * 16777619 mod 2**32`. +func fowlerNollVoMultiply(a int32) int64 { + return (int64(a) + int64(a<<1) + int64(a<<4) + int64(a<<7) + int64(a<<8) + int64(a<<24)) +} + +// Original notes: +// See https://web.archive.org/web/20131019013225/http://home.comcast.net/~bretm/hash/6.html. +func fowlerNollVoMix(a int32) int32 { + a += a << 13 + a ^= int32(uint32(a) >> 7) + a += a << 3 + a ^= int32(uint32(a) >> 17) + a += a << 5 + return a +} + +// utf16Runes converts the given string into a slice of UTF-16 encoded runes. This works by +// determining if each rune is a UTF-16 surrogate pair. If it is, we replace the rune with +// both runes composing the surrogate pair. Otherwise, we leave the original rune alone. +// +// This is a necessary step as existing filters were created in TypeScript, which treated +// strings as encoded in UTF-16, not UTF-8. We need to do this translation for runes that +// fall outside of the basic multilingual plane, or we wont be able to retrieve the original +// identifiers. +func utf16Runes(v string) []rune { + var runes []rune + for _, r := range v { + // If the pair is not surrogate, U+FFFD is returned for both runes + if a, b := utf16.EncodeRune(r); a == unicode.ReplacementChar && b == unicode.ReplacementChar { + runes = append(runes, r) + } else { + runes = append(runes, a, b) + } + } + + return runes +} diff --git a/cmd/precise-code-intel-api-server/internal/api/bloom_filter_test.go b/cmd/precise-code-intel-api-server/internal/api/bloom_filter_test.go new file mode 100644 index 00000000000..03ce0d30c3d --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/api/bloom_filter_test.go @@ -0,0 +1,54 @@ +package api + +import ( + "fmt" + "testing" +) + +func TestTestTypeScriptGeneratedBloomFilters(t *testing.T) { + testCases := []struct { + filterFile string + includeFile string + excludeFile string + }{ + {filterFile: "64kb-16", includeFile: "lorem-ipsum", excludeFile: "corporate-ipsum"}, + {filterFile: "64kb-08", includeFile: "lorem-ipsum", excludeFile: "corporate-ipsum"}, + {filterFile: "64kb-24", includeFile: "lorem-ipsum", excludeFile: "corporate-ipsum"}, + {filterFile: "64kb-32", includeFile: "lorem-ipsum", excludeFile: "corporate-ipsum"}, + {filterFile: "32kb-16", includeFile: "lorem-ipsum", excludeFile: "corporate-ipsum"}, + {filterFile: "32kb-08", includeFile: "lorem-ipsum", excludeFile: "corporate-ipsum"}, + {filterFile: "32kb-24", includeFile: "lorem-ipsum", excludeFile: "corporate-ipsum"}, + {filterFile: "32kb-32", includeFile: "lorem-ipsum", excludeFile: "corporate-ipsum"}, + {filterFile: "96kb-16", includeFile: "lorem-ipsum", excludeFile: "corporate-ipsum"}, + {filterFile: "96kb-08", includeFile: "lorem-ipsum", excludeFile: "corporate-ipsum"}, + {filterFile: "96kb-24", includeFile: "lorem-ipsum", excludeFile: "corporate-ipsum"}, + {filterFile: "96kb-32", includeFile: "lorem-ipsum", excludeFile: "corporate-ipsum"}, + {filterFile: "128kb-16", includeFile: "lorem-ipsum", excludeFile: "corporate-ipsum"}, + {filterFile: "128kb-08", includeFile: "lorem-ipsum", excludeFile: "corporate-ipsum"}, + {filterFile: "128kb-24", includeFile: "lorem-ipsum", excludeFile: "corporate-ipsum"}, + {filterFile: "128kb-32", includeFile: "lorem-ipsum", excludeFile: "corporate-ipsum"}, + {filterFile: "emojis", includeFile: "emojis", excludeFile: "lorem-ipsum"}, + } + + for _, testCase := range testCases { + name := fmt.Sprintf("filter=%s", testCase.filterFile) + + t.Run(name, func(t *testing.T) { + for _, v := range readTestWords(t, testCase.includeFile) { + if exists, err := decodeAndTestFilter(readTestFilter(t, "stress", testCase.filterFile), v); err != nil { + t.Fatalf("unexpected error decoding filter: %s", err) + } else if !exists { + t.Errorf("expected %s to be in bloom filter", v) + } + } + + for _, v := range readTestWords(t, testCase.excludeFile) { + if exists, err := decodeAndTestFilter(readTestFilter(t, "stress", testCase.filterFile), v); err != nil { + t.Fatalf("unexpected error decoding filter: %s", err) + } else if exists { + t.Errorf("expected %s not to be in bloom filter", v) + } + } + }) + } +} diff --git a/cmd/precise-code-intel-api-server/internal/api/cursor.go b/cmd/precise-code-intel-api-server/internal/api/cursor.go new file mode 100644 index 00000000000..7a578915340 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/api/cursor.go @@ -0,0 +1,93 @@ +package api + +import ( + "context" + "encoding/base64" + "encoding/json" + "strings" + + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" +) + +// Cursor holds the complete state necessary to page through a reference result set. +type Cursor struct { + Phase string // common + DumpID int // common + Path string // same-dump/definition-monikers + Line int // same-dump + Character int // same-dump + Monikers []bundles.MonikerData // same-dump/definition-monikers + SkipResults int // same-dump/definition-monikers + Identifier string // same-repo/remote-repo + Scheme string // same-repo/remote-repo + Name string // same-repo/remote-repo + Version string // same-repo/remote-repo + DumpIDs []int // same-repo/remote-repo + TotalDumpsWhenBatching int // same-repo/remote-repo + SkipDumpsWhenBatching int // same-repo/remote-repo + SkipDumpsInBatch int // same-repo/remote-repo + SkipResultsInDump int // same-repo/remote-repo +} + +// EncodeCursor returns an encoding of the given cursor suitable for a URL. +func EncodeCursor(cursor Cursor) string { + rawEncoded, _ := json.Marshal(cursor) + return base64.RawURLEncoding.EncodeToString(rawEncoded) +} + +// decodeCursor is the inverse of EncodeCursor. +func decodeCursor(rawEncoded string) (Cursor, error) { + raw, err := base64.RawURLEncoding.DecodeString(rawEncoded) + if err != nil { + return Cursor{}, err + } + + var cursor Cursor + err = json.Unmarshal([]byte(raw), &cursor) + return cursor, err +} + +// DecodeOrCreateCursor decodes and returns the raw cursor, or creates a new initial page cursor +// if a raw cursor is not supplied. +func DecodeOrCreateCursor(path string, line, character, uploadID int, rawCursor string, db db.DB, bundleManagerClient bundles.BundleManagerClient) (Cursor, error) { + if rawCursor != "" { + cursor, err := decodeCursor(rawCursor) + if err != nil { + return Cursor{}, err + } + + return cursor, nil + } + + dump, exists, err := db.GetDumpByID(context.Background(), uploadID) + if err != nil { + return Cursor{}, err + } + if !exists { + return Cursor{}, ErrMissingDump + } + + pathInBundle := strings.TrimPrefix(path, dump.Root) + bundleClient := bundleManagerClient.BundleClient(dump.ID) + + rangeMonikers, err := bundleClient.MonikersByPosition(context.Background(), pathInBundle, line, character) + if err != nil { + return Cursor{}, err + } + + var flattened []bundles.MonikerData + for _, monikers := range rangeMonikers { + flattened = append(flattened, monikers...) + } + + return Cursor{ + Phase: "same-dump", + DumpID: dump.ID, + Path: pathInBundle, + Line: line, + Character: character, + Monikers: flattened, + SkipResults: 0, + }, nil +} diff --git a/cmd/precise-code-intel-api-server/internal/api/cursor_test.go b/cmd/precise-code-intel-api-server/internal/api/cursor_test.go new file mode 100644 index 00000000000..b71bcf47c7c --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/api/cursor_test.go @@ -0,0 +1,113 @@ +package api + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/mocks" +) + +func TestSerializationRoundTrip(t *testing.T) { + c := Cursor{ + Phase: "same-repo", + DumpID: 42, + Path: "/foo/bar/baz.go", + Line: 10, + Character: 50, + Monikers: []bundles.MonikerData{ + {Kind: "k1", Scheme: "s1", Identifier: "i1", PackageInformationID: "pid1"}, + {Kind: "k2", Scheme: "s2", Identifier: "i2", PackageInformationID: "pid2"}, + {Kind: "k3", Scheme: "s3", Identifier: "i3", PackageInformationID: "pid3"}, + }, + SkipResults: 1, + Identifier: "x", + Scheme: "gomod", + Name: "leftpad", + Version: "0.1.0", + DumpIDs: []int{1, 2, 3, 4, 5}, + TotalDumpsWhenBatching: 5, + SkipDumpsWhenBatching: 4, + SkipDumpsInBatch: 3, + SkipResultsInDump: 2, + } + + roundtripped, err := decodeCursor(EncodeCursor(c)) + if err != nil { + t.Fatalf("unexpected error decoding cursor: %s", err) + } + + if diff := cmp.Diff(c, roundtripped); diff != "" { + t.Errorf("unexpected cursor (-want +got):\n%s", diff) + } +} + +func TestDecodeOrCreateCursor(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + mockBundleClient := mocks.NewMockBundleClient() + + setMockDBGetDumpByID(t, mockDB, map[int]db.Dump{42: testDump1}) + setMockBundleManagerClientBundleClient(t, mockBundleManagerClient, map[int]bundles.BundleClient{42: mockBundleClient}) + setMockBundleClientMonikersByPosition(t, mockBundleClient, "main.go", 10, 20, [][]bundles.MonikerData{{testMoniker1}, {testMoniker2}}) + + expectedCursor := Cursor{ + Phase: "same-dump", + DumpID: 42, + Path: "main.go", + Line: 10, + Character: 20, + Monikers: []bundles.MonikerData{testMoniker1, testMoniker2}, + } + + if cursor, err := DecodeOrCreateCursor("sub1/main.go", 10, 20, 42, "", mockDB, mockBundleManagerClient); err != nil { + t.Fatalf("unexpected error decoding cursor: %s", err) + } else if diff := cmp.Diff(expectedCursor, cursor); diff != "" { + t.Errorf("unexpected cursor (-want +got):\n%s", diff) + } +} + +func TestDecodeOrCreateCursorUnknownDump(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + setMockDBGetDumpByID(t, mockDB, nil) + + if _, err := DecodeOrCreateCursor("sub1/main.go", 10, 20, 42, "", mockDB, mockBundleManagerClient); err != ErrMissingDump { + t.Fatalf("unexpected error decoding cursor. want=%q have =%q", ErrMissingDump, err) + } +} + +func TestDecodeOrCreateCursorExisting(t *testing.T) { + expectedCursor := Cursor{ + Phase: "same-repo", + DumpID: 42, + Path: "/foo/bar/baz.go", + Line: 10, + Character: 50, + Monikers: []bundles.MonikerData{ + {Kind: "k1", Scheme: "s1", Identifier: "i1", PackageInformationID: "pid1"}, + {Kind: "k2", Scheme: "s2", Identifier: "i2", PackageInformationID: "pid2"}, + {Kind: "k3", Scheme: "s3", Identifier: "i3", PackageInformationID: "pid3"}, + }, + SkipResults: 1, + Identifier: "x", + Scheme: "gomod", + Name: "leftpad", + Version: "0.1.0", + DumpIDs: []int{1, 2, 3, 4, 5}, + TotalDumpsWhenBatching: 5, + SkipDumpsWhenBatching: 4, + SkipDumpsInBatch: 3, + SkipResultsInDump: 2, + } + + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + + if cursor, err := DecodeOrCreateCursor("", 0, 0, 0, EncodeCursor(expectedCursor), mockDB, mockBundleManagerClient); err != nil { + t.Fatalf("unexpected error decoding cursor: %s", err) + } else if diff := cmp.Diff(expectedCursor, cursor); diff != "" { + t.Errorf("unexpected cursor (-want +got):\n%s", diff) + } +} diff --git a/cmd/precise-code-intel-api-server/internal/api/definitions.go b/cmd/precise-code-intel-api-server/internal/api/definitions.go new file mode 100644 index 00000000000..ced8ce9370b --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/api/definitions.go @@ -0,0 +1,77 @@ +package api + +import ( + "context" + "strings" + + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" +) + +// Definitions returns the list of source locations that define the symbol at the given position. +// This may include remote definitions if the remote repository is also indexed. +func (api *codeIntelAPI) Definitions(ctx context.Context, file string, line, character, uploadID int) ([]ResolvedLocation, error) { + dump, exists, err := api.db.GetDumpByID(ctx, uploadID) + if err != nil { + return nil, err + } + if !exists { + return nil, ErrMissingDump + } + + pathInBundle := strings.TrimPrefix(file, dump.Root) + bundleClient := api.bundleManagerClient.BundleClient(dump.ID) + return api.definitionsRaw(ctx, dump, bundleClient, pathInBundle, line, character) +} + +func (api *codeIntelAPI) definitionsRaw(ctx context.Context, dump db.Dump, bundleClient bundles.BundleClient, pathInBundle string, line, character int) ([]ResolvedLocation, error) { + locations, err := bundleClient.Definitions(ctx, pathInBundle, line, character) + if err != nil { + return nil, err + } + if len(locations) > 0 { + return resolveLocationsWithDump(dump, locations), nil + } + + rangeMonikers, err := bundleClient.MonikersByPosition(context.Background(), pathInBundle, line, character) + if err != nil { + return nil, err + } + + for _, monikers := range rangeMonikers { + for _, moniker := range monikers { + if moniker.Kind == "import" { + locations, _, err := lookupMoniker(api.db, api.bundleManagerClient, dump.ID, pathInBundle, "definitions", moniker, 0, 0) + if err != nil { + return nil, err + } + if len(locations) > 0 { + return locations, nil + } + } else { + // This symbol was not imported from another database. We search the definitions + // table of our own database in case there was a definition that wasn't properly + // attached to a result set but did have the correct monikers attached. + + locations, _, err := bundleClient.MonikerResults(context.Background(), "definitions", moniker.Scheme, moniker.Identifier, 0, 0) + if err != nil { + return nil, err + } + if len(locations) > 0 { + return resolveLocationsWithDump(dump, locations), nil + } + } + } + } + + return nil, nil +} + +func (api *codeIntelAPI) definitionRaw(ctx context.Context, dump db.Dump, bundleClient bundles.BundleClient, pathInBundle string, line, character int) (ResolvedLocation, bool, error) { + resolved, err := api.definitionsRaw(ctx, dump, bundleClient, pathInBundle, line, character) + if err != nil || len(resolved) == 0 { + return ResolvedLocation{}, false, err + } + + return resolved[0], true, nil +} diff --git a/cmd/precise-code-intel-api-server/internal/api/definitions_test.go b/cmd/precise-code-intel-api-server/internal/api/definitions_test.go new file mode 100644 index 00000000000..1402f08b7f9 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/api/definitions_test.go @@ -0,0 +1,116 @@ +package api + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/mocks" +) + +func TestDefinitions(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + mockBundleClient := mocks.NewMockBundleClient() + + setMockDBGetDumpByID(t, mockDB, map[int]db.Dump{42: testDump1}) + setMockBundleManagerClientBundleClient(t, mockBundleManagerClient, map[int]bundles.BundleClient{42: mockBundleClient}) + setMockBundleClientDefinitions(t, mockBundleClient, "main.go", 10, 50, []bundles.Location{ + {DumpID: 42, Path: "foo.go", Range: testRange1}, + {DumpID: 42, Path: "bar.go", Range: testRange2}, + {DumpID: 42, Path: "baz.go", Range: testRange3}, + }) + + api := New(mockDB, mockBundleManagerClient) + definitions, err := api.Definitions(context.Background(), "sub1/main.go", 10, 50, 42) + if err != nil { + t.Fatalf("expected error getting definitions: %s", err) + } + + expectedDefinitions := []ResolvedLocation{ + {Dump: testDump1, Path: "sub1/foo.go", Range: testRange1}, + {Dump: testDump1, Path: "sub1/bar.go", Range: testRange2}, + {Dump: testDump1, Path: "sub1/baz.go", Range: testRange3}, + } + if diff := cmp.Diff(expectedDefinitions, definitions); diff != "" { + t.Errorf("unexpected definitions (-want +got):\n%s", diff) + } +} + +func TestDefinitionsUnknownDump(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + setMockDBGetDumpByID(t, mockDB, nil) + + api := New(mockDB, mockBundleManagerClient) + if _, err := api.Definitions(context.Background(), "sub1/main.go", 10, 50, 25); err != ErrMissingDump { + t.Fatalf("unexpected error getting definitions. want=%q have=%q", ErrMissingDump, err) + } +} + +func TestDefinitionViaSameDumpMoniker(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + mockBundleClient := mocks.NewMockBundleClient() + + setMockDBGetDumpByID(t, mockDB, map[int]db.Dump{42: testDump1}) + setMockBundleManagerClientBundleClient(t, mockBundleManagerClient, map[int]bundles.BundleClient{42: mockBundleClient}) + setMockBundleClientDefinitions(t, mockBundleClient, "main.go", 10, 50, nil) + setMockBundleClientMonikersByPosition(t, mockBundleClient, "main.go", 10, 50, [][]bundles.MonikerData{{testMoniker2}}) + setMockBundleClientMonikerResults(t, mockBundleClient, "definitions", "gomod", "pad", 0, 0, []bundles.Location{ + {DumpID: 42, Path: "foo.go", Range: testRange1}, + {DumpID: 42, Path: "bar.go", Range: testRange2}, + {DumpID: 42, Path: "baz.go", Range: testRange3}, + }, 3) + + api := New(mockDB, mockBundleManagerClient) + definitions, err := api.Definitions(context.Background(), "sub1/main.go", 10, 50, 42) + if err != nil { + t.Fatalf("expected error getting definitions: %s", err) + } + + expectedDefinitions := []ResolvedLocation{ + {Dump: testDump1, Path: "sub1/foo.go", Range: testRange1}, + {Dump: testDump1, Path: "sub1/bar.go", Range: testRange2}, + {Dump: testDump1, Path: "sub1/baz.go", Range: testRange3}, + } + if diff := cmp.Diff(expectedDefinitions, definitions); diff != "" { + t.Errorf("unexpected definitions (-want +got):\n%s", diff) + } +} + +func TestDefinitionViaRemoteDumpMoniker(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + mockBundleClient1 := mocks.NewMockBundleClient() + mockBundleClient2 := mocks.NewMockBundleClient() + + setMockDBGetDumpByID(t, mockDB, map[int]db.Dump{42: testDump1, 50: testDump2}) + setMockBundleManagerClientBundleClient(t, mockBundleManagerClient, map[int]bundles.BundleClient{42: mockBundleClient1, 50: mockBundleClient2}) + setMockBundleClientDefinitions(t, mockBundleClient1, "main.go", 10, 50, nil) + setMockBundleClientMonikersByPosition(t, mockBundleClient1, "main.go", 10, 50, [][]bundles.MonikerData{{testMoniker1}}) + setMockBundleClientPackageInformation(t, mockBundleClient1, "main.go", "1234", testPackageInformation) + setMockDBGetPackage(t, mockDB, "gomod", "leftpad", "0.1.0", testDump2, true) + setMockBundleClientMonikerResults(t, mockBundleClient2, "definitions", "gomod", "pad", 0, 0, []bundles.Location{ + {DumpID: 50, Path: "foo.go", Range: testRange1}, + {DumpID: 50, Path: "bar.go", Range: testRange2}, + {DumpID: 50, Path: "baz.go", Range: testRange3}, + }, 15) + + api := New(mockDB, mockBundleManagerClient) + definitions, err := api.Definitions(context.Background(), "sub1/main.go", 10, 50, 42) + if err != nil { + t.Fatalf("expected error getting definitions: %s", err) + } + + expectedDefinitions := []ResolvedLocation{ + {Dump: testDump2, Path: "sub2/foo.go", Range: testRange1}, + {Dump: testDump2, Path: "sub2/bar.go", Range: testRange2}, + {Dump: testDump2, Path: "sub2/baz.go", Range: testRange3}, + } + if diff := cmp.Diff(expectedDefinitions, definitions); diff != "" { + t.Errorf("unexpected definitions (-want +got):\n%s", diff) + } +} diff --git a/cmd/precise-code-intel-api-server/internal/api/exists.go b/cmd/precise-code-intel-api-server/internal/api/exists.go new file mode 100644 index 00000000000..1e886fc11fc --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/api/exists.go @@ -0,0 +1,33 @@ +package api + +import ( + "context" + "strings" + + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" +) + +// FindClosestDumps returns the set of dumps that can most accurately answer code intelligence +// queries for the given file. These dump IDs should be subsequently passed to invocations of +// Definitions, References, and Hover. +func (api *codeIntelAPI) FindClosestDumps(ctx context.Context, repositoryID int, commit, file string) ([]db.Dump, error) { + candidates, err := api.db.FindClosestDumps(ctx, repositoryID, commit, file) + if err != nil { + return nil, err + } + + var dumps []db.Dump + for _, dump := range candidates { + exists, err := api.bundleManagerClient.BundleClient(dump.ID).Exists(ctx, strings.TrimPrefix(file, dump.Root)) + if err != nil { + return nil, err + } + if !exists { + continue + } + + dumps = append(dumps, dump) + } + + return dumps, nil +} diff --git a/cmd/precise-code-intel-api-server/internal/api/exists_test.go b/cmd/precise-code-intel-api-server/internal/api/exists_test.go new file mode 100644 index 00000000000..cc7c740c286 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/api/exists_test.go @@ -0,0 +1,51 @@ +package api + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/mocks" +) + +func TestFindClosestDatabase(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + mockBundleClient1 := mocks.NewMockBundleClient() + mockBundleClient2 := mocks.NewMockBundleClient() + mockBundleClient3 := mocks.NewMockBundleClient() + mockBundleClient4 := mocks.NewMockBundleClient() + + setMockDBFindClosestDumps(t, mockDB, 42, testCommit, "s1/main.go", []db.Dump{ + {ID: 50, Root: "s1/"}, + {ID: 51, Root: "s1/"}, + {ID: 52, Root: "s1/"}, + {ID: 53, Root: "s2/"}, + }) + setMockBundleManagerClientBundleClient(t, mockBundleManagerClient, map[int]bundles.BundleClient{ + 50: mockBundleClient1, + 51: mockBundleClient2, + 52: mockBundleClient3, + 53: mockBundleClient4, + }) + setMockBundleClientExists(t, mockBundleClient1, "main.go", true) + setMockBundleClientExists(t, mockBundleClient2, "main.go", false) + setMockBundleClientExists(t, mockBundleClient3, "main.go", true) + setMockBundleClientExists(t, mockBundleClient4, "s1/main.go", false) + + api := New(mockDB, mockBundleManagerClient) + dumps, err := api.FindClosestDumps(context.Background(), 42, testCommit, "s1/main.go") + if err != nil { + t.Fatalf("unexpected error finding closest database: %s", err) + } + + expected := []db.Dump{ + {ID: 50, Root: "s1/"}, + {ID: 52, Root: "s1/"}, + } + if diff := cmp.Diff(expected, dumps); diff != "" { + t.Errorf("unexpected dumps (-want +got):\n%s", diff) + } +} diff --git a/cmd/precise-code-intel-api-server/internal/api/helpers_test.go b/cmd/precise-code-intel-api-server/internal/api/helpers_test.go new file mode 100644 index 00000000000..f166c8fa9f4 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/api/helpers_test.go @@ -0,0 +1,275 @@ +package api + +import ( + "context" + "encoding/hex" + "fmt" + "io/ioutil" + "strings" + "testing" + + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/mocks" +) + +var ( + testCommit = "0000000000000000000000000000000000000000" + testDump1 = db.Dump{ID: 42, Root: "sub1/"} + testDump2 = db.Dump{ID: 50, Root: "sub2/"} + testDump3 = db.Dump{ID: 51, Root: "sub3/"} + testDump4 = db.Dump{ID: 52, Root: "sub4/"} + testMoniker1 = bundles.MonikerData{Kind: "import", Scheme: "gomod", Identifier: "pad", PackageInformationID: "1234"} + testMoniker2 = bundles.MonikerData{Kind: "export", Scheme: "gomod", Identifier: "pad", PackageInformationID: "1234"} + testMoniker3 = bundles.MonikerData{Kind: "export", Scheme: "gomod", Identifier: "pad"} + testPackageInformation = bundles.PackageInformationData{Name: "leftpad", Version: "0.1.0"} + + testRange1 = bundles.Range{ + Start: bundles.Position{Line: 10, Character: 50}, + End: bundles.Position{Line: 10, Character: 55}, + } + testRange2 = bundles.Range{ + Start: bundles.Position{Line: 11, Character: 50}, + End: bundles.Position{Line: 11, Character: 55}, + } + testRange3 = bundles.Range{ + Start: bundles.Position{Line: 12, Character: 50}, + End: bundles.Position{Line: 12, Character: 55}, + } + testRange4 = bundles.Range{ + Start: bundles.Position{Line: 13, Character: 50}, + End: bundles.Position{Line: 13, Character: 55}, + } + testRange5 = bundles.Range{ + Start: bundles.Position{Line: 14, Character: 50}, + End: bundles.Position{Line: 14, Character: 55}, + } +) + +func setMockDBGetDumpByID(t *testing.T, mockDB *mocks.MockDB, dumps map[int]db.Dump) { + mockDB.GetDumpByIDFunc.SetDefaultHook(func(ctx context.Context, id int) (db.Dump, bool, error) { + dump, ok := dumps[id] + return dump, ok, nil + }) +} + +func setMockDBGetPackage(t *testing.T, mockDB *mocks.MockDB, expectedScheme, expectedName, expectedVersion string, dump db.Dump, exists bool) { + mockDB.GetPackageFunc.SetDefaultHook(func(ctx context.Context, scheme, name, version string) (db.Dump, bool, error) { + if scheme != expectedScheme { + t.Errorf("unexpected scheme for GetPackage. want=%s have=%s", expectedScheme, scheme) + } + if name != expectedName { + t.Errorf("unexpected name for GetPackage. want=%s have=%s", expectedName, name) + } + if version != expectedVersion { + t.Errorf("unexpected version for GetPackage. want=%s have=%s", expectedVersion, version) + } + return dump, exists, nil + }) +} + +func setMockDBFindClosestDumps(t *testing.T, mockDB *mocks.MockDB, expectedRepositoryID int, expectedCommit, expectedFile string, dumps []db.Dump) { + mockDB.FindClosestDumpsFunc.SetDefaultHook(func(ctx context.Context, repositoryID int, commit, file string) ([]db.Dump, error) { + if repositoryID != expectedRepositoryID { + t.Errorf("unexpected repository id for FindClosestDumps. want=%d have=%d", expectedRepositoryID, repositoryID) + } + if commit != expectedCommit { + t.Errorf("unexpected commit for FindClosestDumps. want=%s have=%s", expectedCommit, commit) + } + if file != expectedFile { + t.Errorf("unexpected file for FindClosestDumps. want=%s have=%s", expectedFile, file) + } + return dumps, nil + }) +} + +func setMockDBSameRepoPager(t *testing.T, mockDB *mocks.MockDB, expectedRepositoryID int, expectedCommit, expectedScheme, expectedName, expectedVersion string, expectedLimit, totalCount int, pager db.ReferencePager) { + mockDB.SameRepoPagerFunc.SetDefaultHook(func(ctx context.Context, repositoryID int, commit, scheme, name, version string, limit int) (int, db.ReferencePager, error) { + if repositoryID != expectedRepositoryID { + t.Errorf("unexpected repository id for SameRepoPager. want=%v have=%v", expectedRepositoryID, repositoryID) + } + if commit != expectedCommit { + t.Errorf("unexpected commit for SameRepoPager. want=%s have=%s", expectedCommit, commit) + } + if scheme != expectedScheme { + t.Errorf("unexpected scheme for SameRepoPager. want=%s have=%s", expectedScheme, scheme) + } + if name != expectedName { + t.Errorf("unexpected name for SameRepoPager. want=%s have=%s", expectedName, name) + } + if version != expectedVersion { + t.Errorf("unexpected version for SameRepoPager. want=%s have=%s", expectedVersion, version) + } + if limit != expectedLimit { + t.Errorf("unexpected limit for SameRepoPager. want=%d have=%d", expectedLimit, limit) + } + return totalCount, pager, nil + }) +} + +func setMockDBPackageReferencePager(t *testing.T, mockDB *mocks.MockDB, expectedScheme, expectedName, expectedVersion string, expectedRepositoryID, expectedLimit int, totalCount int, pager db.ReferencePager) { + mockDB.PackageReferencePagerFunc.SetDefaultHook(func(ctx context.Context, scheme, name, version string, repositoryID, limit int) (int, db.ReferencePager, error) { + if scheme != expectedScheme { + t.Errorf("unexpected scheme for PackageReferencePager. want=%s have=%s", expectedScheme, scheme) + } + if name != expectedName { + t.Errorf("unexpected name for PackageReferencePager. want=%s have=%s", expectedName, name) + } + if version != expectedVersion { + t.Errorf("unexpected version for PackageReferencePager. want=%s have=%s", expectedVersion, version) + } + if repositoryID != expectedRepositoryID { + t.Errorf("unexpected repository id for PackageReferencePager. want=%d have=%d", expectedRepositoryID, repositoryID) + } + if limit != expectedLimit { + t.Errorf("unexpected limit for PackageReferencePager. want=%d have=%d", expectedLimit, limit) + } + return totalCount, pager, nil + }) +} + +func setMockReferencePagerPageFromOffset(t *testing.T, mockReferencePager *mocks.MockReferencePager, expectedOffset int, references []db.Reference) { + mockReferencePager.PageFromOffsetFunc.SetDefaultHook(func(offset int) ([]db.Reference, error) { + if offset != expectedOffset { + t.Errorf("unexpected offset for PageFromOffset. want=%d have=%d", expectedOffset, offset) + } + return references, nil + }) +} + +func setMockBundleManagerClientBundleClient(t *testing.T, mockBundleManagerClient *mocks.MockBundleManagerClient, bundleClients map[int]bundles.BundleClient) { + mockBundleManagerClient.BundleClientFunc.SetDefaultHook(func(bundleID int) bundles.BundleClient { + bundleClient, ok := bundleClients[bundleID] + if !ok { + t.Errorf("unexpected bundle id for BundleClient: %d", bundleID) + } + + return bundleClient + }) +} + +func setMockBundleClientExists(t *testing.T, mockBundleClient *mocks.MockBundleClient, expectedPath string, exists bool) { + mockBundleClient.ExistsFunc.SetDefaultHook(func(ctx context.Context, path string) (bool, error) { + if path != expectedPath { + t.Errorf("unexpected path for Exists. want=%s have=%s", expectedPath, path) + } + return exists, nil + }) +} + +func setMockBundleClientDefinitions(t *testing.T, mockBundleClient *mocks.MockBundleClient, expectedPath string, expectedLine, expectedCharacter int, locations []bundles.Location) { + mockBundleClient.DefinitionsFunc.SetDefaultHook(func(ctx context.Context, path string, line, character int) ([]bundles.Location, error) { + if path != expectedPath { + t.Errorf("unexpected path for Definitions. want=%s have=%s", expectedPath, path) + } + if line != expectedLine { + t.Errorf("unexpected line for Definitions. want=%d have=%d", expectedLine, line) + } + if character != expectedCharacter { + t.Errorf("unexpected character for Definitions. want=%d have=%d", expectedCharacter, character) + } + return locations, nil + }) +} + +func setMockBundleClientReferences(t *testing.T, mockBundleClient *mocks.MockBundleClient, expectedPath string, expectedLine, expectedCharacter int, locations []bundles.Location) { + mockBundleClient.ReferencesFunc.SetDefaultHook(func(ctx context.Context, path string, line, character int) ([]bundles.Location, error) { + if path != expectedPath { + t.Errorf("unexpected path for References. want=%s have=%s", expectedPath, path) + } + if line != expectedLine { + t.Errorf("unexpected line for References. want=%d have=%d", expectedLine, line) + } + if character != expectedCharacter { + t.Errorf("unexpected character for References. want=%d have=%d", expectedCharacter, character) + } + return locations, nil + }) +} + +func setMockBundleClientHover(t *testing.T, mockBundleClient *mocks.MockBundleClient, expectedPath string, expectedLine, expectedCharacter int, text string, r bundles.Range, exists bool) { + mockBundleClient.HoverFunc.SetDefaultHook(func(ctx context.Context, path string, line, character int) (string, bundles.Range, bool, error) { + if path != expectedPath { + t.Errorf("unexpected path Hover. want=%s have=%s", expectedPath, path) + } + if line != expectedLine { + t.Errorf("unexpected line Hover. want=%d have=%d", expectedLine, line) + } + if character != expectedCharacter { + t.Errorf("unexpected character Hover. want=%d have=%d", expectedCharacter, character) + } + return text, r, exists, nil + }) +} + +func setMockBundleClientMonikersByPosition(t *testing.T, mockBundleClient *mocks.MockBundleClient, expectedPath string, expectedLine, expectedCharacter int, monikers [][]bundles.MonikerData) { + mockBundleClient.MonikersByPositionFunc.SetDefaultHook(func(ctx context.Context, path string, line, character int) ([][]bundles.MonikerData, error) { + if path != expectedPath { + t.Fatalf("unexpected path for MonikersByPosition. want=%s have=%s", expectedPath, path) + } + if line != expectedLine { + t.Fatalf("unexpected line for MonikersByPosition. want=%v have=%v", expectedLine, line) + } + if character != expectedCharacter { + t.Fatalf("unexpected character for MonikersByPosition. want=%v have=%v", expectedCharacter, character) + } + + return monikers, nil + }) +} + +func setMockBundleClientMonikerResults(t *testing.T, mockBundleClient *mocks.MockBundleClient, expectedModelType, expectedScheme, expectedIdentifier string, expectedSkip, expectedTake int, locations []bundles.Location, totalCount int) { + mockBundleClient.MonikerResultsFunc.SetDefaultHook(func(ctx context.Context, modelType, scheme, identifier string, skip, take int) ([]bundles.Location, int, error) { + if modelType != expectedModelType { + t.Errorf("unexpected model type for MonikerResults. want=%s have=%s", expectedModelType, modelType) + } + if scheme != expectedScheme { + t.Errorf("unexpected scheme for MonikerResults. want=%s have=%s", expectedScheme, scheme) + } + if identifier != expectedIdentifier { + t.Errorf("unexpected identifier for MonikerResults. want=%s have=%s", expectedIdentifier, identifier) + } + if skip != expectedSkip { + t.Errorf("unexpected skip for MonikerResults. want=%d have=%d", expectedSkip, skip) + } + if take != expectedTake { + t.Errorf("unexpected take for MonikerResults. want=%d have=%d", expectedTake, take) + } + return locations, totalCount, nil + }) +} + +func setMockBundleClientPackageInformation(t *testing.T, mockBundleClient *mocks.MockBundleClient, expectedPath, expectedPackageInformationID string, packageInformation bundles.PackageInformationData) { + mockBundleClient.PackageInformationFunc.SetDefaultHook(func(ctx context.Context, path, packageInformationID string) (bundles.PackageInformationData, error) { + if path != expectedPath { + t.Errorf("unexpected path for PackageInformation. want=%s have=%s", expectedPath, path) + } + if packageInformationID != expectedPackageInformationID { + t.Errorf("unexpected package information id for PackageInformation. want=%s have=%s", expectedPackageInformationID, packageInformationID) + } + return packageInformation, nil + }) +} + +func readTestFilter(t *testing.T, dirname, filename string) []byte { + content, err := ioutil.ReadFile(fmt.Sprintf("../../testdata/filters/%s/%s", dirname, filename)) + if err != nil { + t.Fatalf("unexpected error reading: %s", err) + } + + raw, err := hex.DecodeString(strings.TrimSpace(string(content))) + if err != nil { + t.Fatalf("unexpected error decoding: %s", err) + } + + return raw +} + +func readTestWords(t *testing.T, filename string) []string { + content, err := ioutil.ReadFile(fmt.Sprintf("../../testdata/words/%s", filename)) + if err != nil { + t.Fatalf("unexpected error reading %s: %s", filename, err) + } + + return strings.Split(strings.TrimSpace(string(content)), "\n") +} diff --git a/cmd/precise-code-intel-api-server/internal/api/hover.go b/cmd/precise-code-intel-api-server/internal/api/hover.go new file mode 100644 index 00000000000..0b644d1a551 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/api/hover.go @@ -0,0 +1,40 @@ +package api + +import ( + "context" + "strings" + + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" +) + +// Hover returns the hover text and range for the symbol at the given position. +func (api *codeIntelAPI) Hover(ctx context.Context, file string, line, character, uploadID int) (string, bundles.Range, bool, error) { + dump, exists, err := api.db.GetDumpByID(ctx, uploadID) + if err != nil { + return "", bundles.Range{}, false, err + } + if !exists { + return "", bundles.Range{}, false, ErrMissingDump + } + + pathInBundle := strings.TrimPrefix(file, dump.Root) + bundleClient := api.bundleManagerClient.BundleClient(dump.ID) + + text, rn, exists, err := bundleClient.Hover(ctx, pathInBundle, line, character) + if err != nil { + return "", bundles.Range{}, false, err + } + if exists { + return text, rn, true, nil + } + + definition, exists, err := api.definitionRaw(ctx, dump, bundleClient, pathInBundle, line, character) + if err != nil || !exists { + return "", bundles.Range{}, false, err + } + + pathInDefinitionBundle := strings.TrimPrefix(definition.Path, definition.Dump.Root) + definitionBundleClient := api.bundleManagerClient.BundleClient(definition.Dump.ID) + + return definitionBundleClient.Hover(ctx, pathInDefinitionBundle, definition.Range.Start.Line, definition.Range.Start.Character) +} diff --git a/cmd/precise-code-intel-api-server/internal/api/hover_test.go b/cmd/precise-code-intel-api-server/internal/api/hover_test.go new file mode 100644 index 00000000000..e0ccb74f4aa --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/api/hover_test.go @@ -0,0 +1,108 @@ +package api + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/mocks" +) + +func TestHover(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + mockBundleClient := mocks.NewMockBundleClient() + + setMockDBGetDumpByID(t, mockDB, map[int]db.Dump{42: testDump1}) + setMockBundleManagerClientBundleClient(t, mockBundleManagerClient, map[int]bundles.BundleClient{42: mockBundleClient}) + setMockBundleClientHover(t, mockBundleClient, "main.go", 10, 50, "text", testRange1, true) + + api := New(mockDB, mockBundleManagerClient) + text, r, exists, err := api.Hover(context.Background(), "sub1/main.go", 10, 50, 42) + if err != nil { + t.Fatalf("expected error getting hover text: %s", err) + } + if !exists { + t.Fatalf("expected hover text to exist.") + } + + if text != "text" { + t.Errorf("unexpected text. want=%s have=%s", "text", text) + } + if diff := cmp.Diff(testRange1, r); diff != "" { + t.Errorf("unexpected range (-want +got):\n%s", diff) + } +} + +func TestHoverUnknownDump(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + setMockDBGetDumpByID(t, mockDB, nil) + + api := New(mockDB, mockBundleManagerClient) + if _, _, _, err := api.Hover(context.Background(), "sub1/main.go", 10, 50, 42); err != ErrMissingDump { + t.Fatalf("unexpected error getting hover text. want=%q have=%q", ErrMissingDump, err) + } +} + +func TestHoverRemoteDefinitionHoverText(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + mockBundleClient1 := mocks.NewMockBundleClient() + mockBundleClient2 := mocks.NewMockBundleClient() + + setMockDBGetDumpByID(t, mockDB, map[int]db.Dump{42: testDump1, 50: testDump2}) + setMockBundleManagerClientBundleClient(t, mockBundleManagerClient, map[int]bundles.BundleClient{42: mockBundleClient1, 50: mockBundleClient2}) + setMockBundleClientHover(t, mockBundleClient1, "main.go", 10, 50, "", bundles.Range{}, false) + setMockBundleClientDefinitions(t, mockBundleClient1, "main.go", 10, 50, nil) + setMockBundleClientMonikersByPosition(t, mockBundleClient1, "main.go", 10, 50, [][]bundles.MonikerData{{testMoniker1}}) + setMockBundleClientPackageInformation(t, mockBundleClient1, "main.go", "1234", testPackageInformation) + setMockDBGetPackage(t, mockDB, "gomod", "leftpad", "0.1.0", testDump2, true) + setMockBundleClientMonikerResults(t, mockBundleClient2, "definitions", "gomod", "pad", 0, 0, []bundles.Location{ + {DumpID: 50, Path: "foo.go", Range: testRange1}, + {DumpID: 50, Path: "bar.go", Range: testRange2}, + {DumpID: 50, Path: "baz.go", Range: testRange3}, + }, 15) + setMockBundleClientHover(t, mockBundleClient2, "foo.go", 10, 50, "text", testRange4, true) + + api := New(mockDB, mockBundleManagerClient) + text, r, exists, err := api.Hover(context.Background(), "sub1/main.go", 10, 50, 42) + if err != nil { + t.Fatalf("expected error getting hover text: %s", err) + } + if !exists { + t.Fatalf("expected hover text to exist.") + } + + if text != "text" { + t.Errorf("unexpected text. want=%s have=%s", "text", text) + } + if diff := cmp.Diff(testRange4, r); diff != "" { + t.Errorf("unexpected range (-want +got):\n%s", diff) + } +} + +func TestHoverUnknownDefinition(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + mockBundleClient := mocks.NewMockBundleClient() + + setMockDBGetDumpByID(t, mockDB, map[int]db.Dump{42: testDump1}) + setMockBundleManagerClientBundleClient(t, mockBundleManagerClient, map[int]bundles.BundleClient{42: mockBundleClient}) + setMockBundleClientHover(t, mockBundleClient, "main.go", 10, 50, "", bundles.Range{}, false) + setMockBundleClientDefinitions(t, mockBundleClient, "main.go", 10, 50, nil) + setMockBundleClientMonikersByPosition(t, mockBundleClient, "main.go", 10, 50, [][]bundles.MonikerData{{testMoniker1}}) + setMockBundleClientPackageInformation(t, mockBundleClient, "main.go", "1234", testPackageInformation) + setMockDBGetPackage(t, mockDB, "gomod", "leftpad", "0.1.0", db.Dump{}, false) + + api := New(mockDB, mockBundleManagerClient) + _, _, exists, err := api.Hover(context.Background(), "sub1/main.go", 10, 50, 42) + if err != nil { + t.Fatalf("unexpected error getting hover text: %s", err) + } + if exists { + t.Errorf("unexpected hover text") + } +} diff --git a/cmd/precise-code-intel-api-server/internal/api/locations.go b/cmd/precise-code-intel-api-server/internal/api/locations.go new file mode 100644 index 00000000000..ed8a5af6788 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/api/locations.go @@ -0,0 +1,35 @@ +package api + +import ( + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" +) + +type ResolvedLocation struct { + Dump db.Dump `json:"dump"` + Path string `json:"path"` + Range bundles.Range `json:"range"` +} + +func sliceLocations(locations []bundles.Location, lo, hi int) []bundles.Location { + if lo >= len(locations) { + return nil + } + if hi >= len(locations) { + hi = len(locations) + } + return locations[lo:hi] +} + +func resolveLocationsWithDump(dump db.Dump, locations []bundles.Location) []ResolvedLocation { + var resolvedLocations []ResolvedLocation + for _, location := range locations { + resolvedLocations = append(resolvedLocations, ResolvedLocation{ + Dump: dump, + Path: dump.Root + location.Path, + Range: location.Range, + }) + } + + return resolvedLocations +} diff --git a/cmd/precise-code-intel-api-server/internal/api/monikers.go b/cmd/precise-code-intel-api-server/internal/api/monikers.go new file mode 100644 index 00000000000..c57202413db --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/api/monikers.go @@ -0,0 +1,40 @@ +package api + +import ( + "context" + + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" +) + +func lookupMoniker( + db db.DB, + bundleManagerClient bundles.BundleManagerClient, + dumpID int, + path string, + modelType string, + moniker bundles.MonikerData, + skip int, + take int, +) ([]ResolvedLocation, int, error) { + if moniker.PackageInformationID == "" { + return nil, 0, nil + } + + pid, err := bundleManagerClient.BundleClient(dumpID).PackageInformation(context.Background(), path, moniker.PackageInformationID) + if err != nil { + return nil, 0, err + } + + dump, exists, err := db.GetPackage(context.Background(), moniker.Scheme, pid.Name, pid.Version) + if err != nil || !exists { + return nil, 0, err + } + + locations, count, err := bundleManagerClient.BundleClient(dump.ID).MonikerResults(context.Background(), modelType, moniker.Scheme, moniker.Identifier, skip, take) + if err != nil { + return nil, 0, err + } + + return resolveLocationsWithDump(dump, locations), count, nil +} diff --git a/cmd/precise-code-intel-api-server/internal/api/monikers_test.go b/cmd/precise-code-intel-api-server/internal/api/monikers_test.go new file mode 100644 index 00000000000..63faed7a2bd --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/api/monikers_test.go @@ -0,0 +1,78 @@ +package api + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/mocks" +) + +func TestLookupMoniker(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + mockBundleClient1 := mocks.NewMockBundleClient() + mockBundleClient2 := mocks.NewMockBundleClient() + + setMockBundleManagerClientBundleClient(t, mockBundleManagerClient, map[int]bundles.BundleClient{42: mockBundleClient1, 50: mockBundleClient2}) + setMockBundleClientPackageInformation(t, mockBundleClient1, "sub2/main.go", "1234", testPackageInformation) + setMockDBGetPackage(t, mockDB, "gomod", "leftpad", "0.1.0", testDump2, true) + setMockBundleClientMonikerResults(t, mockBundleClient2, "definitions", "gomod", "pad", 10, 5, []bundles.Location{ + {DumpID: 42, Path: "foo.go", Range: testRange1}, + {DumpID: 42, Path: "bar.go", Range: testRange2}, + {DumpID: 42, Path: "baz.go", Range: testRange3}, + {DumpID: 42, Path: "bar.go", Range: testRange4}, + {DumpID: 42, Path: "baz.go", Range: testRange5}, + }, 15) + + locations, totalCount, err := lookupMoniker(mockDB, mockBundleManagerClient, 42, "sub2/main.go", "definitions", testMoniker2, 10, 5) + if err != nil { + t.Fatalf("unexpected error querying moniker: %s", err) + } + if totalCount != 15 { + t.Errorf("unexpected total count. want=%d have=%d", 5, totalCount) + } + + expectedLocations := []ResolvedLocation{ + {Dump: testDump2, Path: "sub2/foo.go", Range: testRange1}, + {Dump: testDump2, Path: "sub2/bar.go", Range: testRange2}, + {Dump: testDump2, Path: "sub2/baz.go", Range: testRange3}, + {Dump: testDump2, Path: "sub2/bar.go", Range: testRange4}, + {Dump: testDump2, Path: "sub2/baz.go", Range: testRange5}, + } + if diff := cmp.Diff(expectedLocations, locations); diff != "" { + t.Errorf("unexpected definitions (-want +got):\n%s", diff) + } +} + +func TestLookupMonikerNoPackageInformationID(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + + _, totalCount, err := lookupMoniker(mockDB, mockBundleManagerClient, 42, "sub/main.go", "definitions", testMoniker3, 10, 5) + if err != nil { + t.Fatalf("unexpected error querying moniker: %s", err) + } + if totalCount != 0 { + t.Errorf("unexpected total count. want=%d have=%d", 0, totalCount) + } +} + +func TestLookupMonikerNoPackage(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + mockBundleClient := mocks.NewMockBundleClient() + + setMockBundleManagerClientBundleClient(t, mockBundleManagerClient, map[int]bundles.BundleClient{42: mockBundleClient}) + setMockBundleClientPackageInformation(t, mockBundleClient, "main.go", "1234", testPackageInformation) + setMockDBGetPackage(t, mockDB, "gomod", "leftpad", "0.1.0", db.Dump{}, false) + + _, totalCount, err := lookupMoniker(mockDB, mockBundleManagerClient, 42, "main.go", "definitions", testMoniker1, 10, 5) + if err != nil { + t.Fatalf("unexpected error querying moniker: %s", err) + } + if totalCount != 0 { + t.Errorf("unexpected total count. want=%d have=%d", 0, totalCount) + } +} diff --git a/cmd/precise-code-intel-api-server/internal/api/references.go b/cmd/precise-code-intel-api-server/internal/api/references.go new file mode 100644 index 00000000000..c04a2e2613f --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/api/references.go @@ -0,0 +1,351 @@ +package api + +import ( + "context" + "fmt" + + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" +) + +// References returns the list of source locations that reference the symbol at the given position. +// This may include references from other dumps and repositories. +func (api *codeIntelAPI) References(ctx context.Context, repositoryID int, commit string, limit int, cursor Cursor) ([]ResolvedLocation, Cursor, bool, error) { + rpr := &ReferencePageResolver{ + db: api.db, + bundleManagerClient: api.bundleManagerClient, + repositoryID: repositoryID, + commit: commit, + limit: limit, + } + + return rpr.resolvePage(ctx, cursor) +} + +type ReferencePageResolver struct { + db db.DB + bundleManagerClient bundles.BundleManagerClient + repositoryID int + commit string + remoteDumpLimit int + limit int +} + +func (s *ReferencePageResolver) resolvePage(ctx context.Context, cursor Cursor) ([]ResolvedLocation, Cursor, bool, error) { + var allLocations []ResolvedLocation + + for { + locations, newCursor, hasNewCursor, err := s.dispatchCursorHandler(ctx, cursor) + if err != nil { + return nil, Cursor{}, false, err + } + + s.limit -= len(locations) + allLocations = append(allLocations, locations...) + + if !hasNewCursor || s.limit <= 0 { + return allLocations, newCursor, hasNewCursor, err + } + + cursor = newCursor + } +} + +func (s *ReferencePageResolver) dispatchCursorHandler(ctx context.Context, cursor Cursor) ([]ResolvedLocation, Cursor, bool, error) { + fns := map[string]func(context.Context, Cursor) ([]ResolvedLocation, Cursor, bool, error){ + "same-dump": s.handleSameDumpCursor, + "definition-monikers": s.handleDefinitionMonikersCursor, + "same-repo": s.handleSameRepoCursor, + "remote-repo": s.handleRemoteRepoCursor, + } + + fn, exists := fns[cursor.Phase] + if !exists { + return nil, Cursor{}, false, fmt.Errorf("unknown cursor phase %s", cursor.Phase) + } + + return fn(ctx, cursor) +} + +func (s *ReferencePageResolver) handleSameDumpCursor(ctx context.Context, cursor Cursor) ([]ResolvedLocation, Cursor, bool, error) { + dump, exists, err := s.db.GetDumpByID(ctx, cursor.DumpID) + if err != nil { + return nil, Cursor{}, false, err + } + if !exists { + return nil, Cursor{}, false, ErrMissingDump + } + bundleClient := s.bundleManagerClient.BundleClient(dump.ID) + + locations, err := bundleClient.References(ctx, cursor.Path, cursor.Line, cursor.Character) + if err != nil { + return nil, Cursor{}, false, err + } + + hashLocation := func(location bundles.Location) string { + return fmt.Sprintf( + "%s:%d:%d:%d:%d", + location.Path, + location.Range.Start.Line, + location.Range.Start.Character, + location.Range.End.Line, + location.Range.End.Character, + ) + } + + dumpIDs := map[string]struct{}{} + for _, location := range locations { + dumpIDs[hashLocation(location)] = struct{}{} + } + + // Search the references table of the current dump. This search is necessary because + // we want a 'Find References' operation on a reference to also return references to + // the governing definition, and those may not be fully linked in the LSIF data. This + // method returns a cursor if there are reference rows remaining for a subsequent page. + for _, moniker := range cursor.Monikers { + results, _, err := bundleClient.MonikerResults(ctx, "reference", moniker.Scheme, moniker.Identifier, 0, 0) + if err != nil { + return nil, Cursor{}, false, err + } + + for _, location := range results { + if _, ok := dumpIDs[hashLocation(location)]; !ok { + locations = append(locations, location) + } + } + } + + resolvedLocations := resolveLocationsWithDump(dump, sliceLocations(locations, cursor.SkipResults, cursor.SkipResults+s.limit)) + + if newOffset := cursor.SkipResults + s.limit; newOffset <= len(locations) { + newCursor := Cursor{ + Phase: cursor.Phase, + DumpID: cursor.DumpID, + Path: cursor.Path, + Line: cursor.Line, + Character: cursor.Character, + Monikers: cursor.Monikers, + SkipResults: newOffset, + } + return resolvedLocations, newCursor, true, nil + } + + newCursor := Cursor{ + DumpID: cursor.DumpID, + Phase: "definition-monikers", + Path: cursor.Path, + Monikers: cursor.Monikers, + SkipResults: 0, + } + return resolvedLocations, newCursor, true, nil +} + +func (s *ReferencePageResolver) handleDefinitionMonikersCursor(ctx context.Context, cursor Cursor) ([]ResolvedLocation, Cursor, bool, error) { + var hasNextPhaseCursor = false + var nextPhaseCursor Cursor + for _, moniker := range cursor.Monikers { + if moniker.PackageInformationID == "" { + continue + } + + packageInformation, err := s.bundleManagerClient.BundleClient(cursor.DumpID).PackageInformation(ctx, cursor.Path, moniker.PackageInformationID) + if err != nil { + return nil, Cursor{}, false, err + } + + hasNextPhaseCursor = true + nextPhaseCursor = Cursor{ + DumpID: cursor.DumpID, + Phase: "same-repo", + Scheme: moniker.Scheme, + Identifier: moniker.Identifier, + Name: packageInformation.Name, + Version: packageInformation.Version, + DumpIDs: nil, + TotalDumpsWhenBatching: 0, + SkipDumpsWhenBatching: 0, + SkipDumpsInBatch: 0, + SkipResultsInDump: 0, + } + break + } + + for _, moniker := range cursor.Monikers { + if moniker.Kind != "import" { + continue + } + + locations, count, err := lookupMoniker(s.db, s.bundleManagerClient, cursor.DumpID, cursor.Path, "reference", moniker, cursor.SkipResults, s.limit) + if err != nil { + return nil, Cursor{}, false, err + } + if len(locations) == 0 { + continue + } + + if newOffset := cursor.SkipResults + len(locations); newOffset < count { + newCursor := Cursor{ + Phase: cursor.Phase, + DumpID: cursor.DumpID, + Path: cursor.Path, + Monikers: cursor.Monikers, + SkipResults: newOffset, + } + return locations, newCursor, true, nil + } + + return locations, nextPhaseCursor, hasNextPhaseCursor, nil + } + + return nil, nextPhaseCursor, hasNextPhaseCursor, nil + +} + +func (s *ReferencePageResolver) handleSameRepoCursor(ctx context.Context, cursor Cursor) ([]ResolvedLocation, Cursor, bool, error) { + locations, newCursor, hasNewCursor, err := s.resolveLocationsViaReferencePager(ctx, cursor, func(ctx context.Context) (int, db.ReferencePager, error) { + return s.db.SameRepoPager(ctx, s.repositoryID, s.commit, cursor.Scheme, cursor.Name, cursor.Version, s.remoteDumpLimit) + }) + if err != nil || hasNewCursor { + return locations, newCursor, hasNewCursor, err + } + + newCursor = Cursor{ + DumpID: cursor.DumpID, + Phase: "remote-repo", + Scheme: cursor.Scheme, + Identifier: cursor.Identifier, + Name: cursor.Name, + Version: cursor.Version, + DumpIDs: nil, + TotalDumpsWhenBatching: 0, + SkipDumpsWhenBatching: 0, + SkipDumpsInBatch: 0, + SkipResultsInDump: 0, + } + return locations, newCursor, true, nil +} + +func (s *ReferencePageResolver) handleRemoteRepoCursor(ctx context.Context, cursor Cursor) ([]ResolvedLocation, Cursor, bool, error) { + return s.resolveLocationsViaReferencePager(ctx, cursor, func(ctx context.Context) (int, db.ReferencePager, error) { + return s.db.PackageReferencePager(ctx, cursor.Scheme, cursor.Name, cursor.Version, s.repositoryID, s.remoteDumpLimit) + }) +} + +func (s *ReferencePageResolver) resolveLocationsViaReferencePager(ctx context.Context, cursor Cursor, createPager func(context.Context) (int, db.ReferencePager, error)) ([]ResolvedLocation, Cursor, bool, error) { + dumpID := cursor.DumpID + scheme := cursor.Scheme + identifier := cursor.Identifier + limit := s.limit + + if len(cursor.DumpIDs) == 0 { + totalCount, pager, err := createPager(ctx) + if err != nil { + return nil, Cursor{}, false, err + } + + identifier := cursor.Identifier + offset := cursor.SkipDumpsWhenBatching + limit := s.remoteDumpLimit + newOffset := offset + + var packageRefs []db.Reference + for len(packageRefs) < limit && newOffset < totalCount { + page, err := pager.PageFromOffset(newOffset) + if err != nil { + return nil, Cursor{}, false, pager.CloseTx(err) + } + + if len(page) == 0 { + // Shouldn't happen, but just in case of a bug we + // don't want this to throw up into an infinite loop. + break + } + + filtered, scanned := applyBloomFilter(page, identifier, limit-len(packageRefs)) + packageRefs = append(packageRefs, filtered...) + newOffset += scanned + } + + var dumpIDs []int + for _, ref := range packageRefs { + dumpIDs = append(dumpIDs, ref.DumpID) + } + + cursor.DumpIDs = dumpIDs + cursor.SkipDumpsWhenBatching = newOffset + cursor.TotalDumpsWhenBatching = totalCount + + if err := pager.CloseTx(nil); err != nil { + return nil, Cursor{}, false, err + } + } + + for i, batchDumpID := range cursor.DumpIDs { + // Skip the remote reference that show up for ourselves - we've already gathered + // these in the previous step of the references query. + if i < cursor.SkipDumpsInBatch || batchDumpID == dumpID { + continue + } + + dump, exists, err := s.db.GetDumpByID(ctx, batchDumpID) + if err != nil { + return nil, Cursor{}, false, err + } + if !exists { + continue + } + bundleClient := s.bundleManagerClient.BundleClient(batchDumpID) + + results, count, err := bundleClient.MonikerResults(ctx, "reference", scheme, identifier, cursor.SkipResultsInDump, limit) + if err != nil { + return nil, Cursor{}, false, err + } + if len(results) == 0 { + continue + } + resolvedLocations := resolveLocationsWithDump(dump, results) + + if newResultOffset := cursor.SkipResultsInDump + len(results); newResultOffset < count { + newCursor := cursor + newCursor.SkipResultsInDump = newResultOffset + return resolvedLocations, newCursor, true, nil + } + + if i+1 < len(cursor.DumpIDs) { + newCursor := cursor + newCursor.SkipDumpsInBatch = i + 1 + newCursor.SkipResultsInDump = 0 + return resolvedLocations, newCursor, true, nil + } + + if cursor.SkipDumpsWhenBatching < cursor.TotalDumpsWhenBatching { + newCursor := cursor + newCursor.DumpIDs = []int{} + newCursor.SkipDumpsInBatch = 0 + newCursor.SkipResultsInDump = 0 + return resolvedLocations, newCursor, true, nil + } + + return resolvedLocations, Cursor{}, false, nil + } + + return nil, Cursor{}, false, nil +} + +func applyBloomFilter(refs []db.Reference, identifier string, limit int) ([]db.Reference, int) { + var filteredReferences []db.Reference + for i, ref := range refs { + test, err := decodeAndTestFilter([]byte(ref.Filter), identifier) + if err != nil || !test { + continue + } + + filteredReferences = append(filteredReferences, ref) + + if len(filteredReferences) >= limit { + return filteredReferences, i + 1 + } + } + + return filteredReferences, len(refs) +} diff --git a/cmd/precise-code-intel-api-server/internal/api/references_test.go b/cmd/precise-code-intel-api-server/internal/api/references_test.go new file mode 100644 index 00000000000..d6b9664fb8e --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/api/references_test.go @@ -0,0 +1,695 @@ +package api + +import ( + "context" + "fmt" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/mocks" +) + +func TestHandleSameDumpCursor(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + mockBundleClient := mocks.NewMockBundleClient() + + setMockDBGetDumpByID(t, mockDB, map[int]db.Dump{42: testDump1}) + setMockBundleManagerClientBundleClient(t, mockBundleManagerClient, map[int]bundles.BundleClient{42: mockBundleClient}) + setMockBundleClientReferences(t, mockBundleClient, "main.go", 23, 34, []bundles.Location{ + {DumpID: 42, Path: "foo.go", Range: testRange1}, + {DumpID: 42, Path: "bar.go", Range: testRange2}, + {DumpID: 42, Path: "baz.go", Range: testRange3}, + }) + setMockBundleClientMonikerResults(t, mockBundleClient, "reference", "gomod", "pad", 0, 0, []bundles.Location{ + {DumpID: 42, Path: "foo.go", Range: testRange1}, + {DumpID: 42, Path: "bonk.go", Range: testRange4}, + {DumpID: 42, Path: "quux.go", Range: testRange5}, + }, 3) + + rpr := &ReferencePageResolver{ + db: mockDB, + bundleManagerClient: mockBundleManagerClient, + repositoryID: 100, + commit: testCommit, + limit: 5, + } + + t.Run("partial results", func(t *testing.T) { + references, newCursor, hasNewCursor, err := rpr.dispatchCursorHandler(context.Background(), Cursor{ + Phase: "same-dump", + DumpID: 42, + Path: "main.go", + Line: 23, + Character: 34, + Monikers: []bundles.MonikerData{{Kind: "export", Scheme: "gomod", Identifier: "pad"}}, + SkipResults: 0, + }) + if err != nil { + t.Fatalf("expected error getting references: %s", err) + } + + expectedReferences := []ResolvedLocation{ + {Dump: testDump1, Path: "sub1/foo.go", Range: testRange1}, + {Dump: testDump1, Path: "sub1/bar.go", Range: testRange2}, + {Dump: testDump1, Path: "sub1/baz.go", Range: testRange3}, + {Dump: testDump1, Path: "sub1/bonk.go", Range: testRange4}, + {Dump: testDump1, Path: "sub1/quux.go", Range: testRange5}, + } + if diff := cmp.Diff(expectedReferences, references); diff != "" { + t.Errorf("unexpected references (-want +got):\n%s", diff) + } + + expectedNewCursor := Cursor{ + Phase: "same-dump", + DumpID: 42, + Path: "main.go", + Line: 23, + Character: 34, + Monikers: []bundles.MonikerData{{Kind: "export", Scheme: "gomod", Identifier: "pad"}}, + SkipResults: 5, + } + if !hasNewCursor { + t.Errorf("expected new cursor") + } else if diff := cmp.Diff(expectedNewCursor, newCursor); diff != "" { + t.Errorf("unexpected new cursor (-want +got):\n%s", diff) + } + }) + + t.Run("end of result set", func(t *testing.T) { + references, newCursor, hasNewCursor, err := rpr.dispatchCursorHandler(context.Background(), Cursor{ + Phase: "same-dump", + DumpID: 42, + Path: "main.go", + Line: 23, + Character: 34, + Monikers: []bundles.MonikerData{{Kind: "export", Scheme: "gomod", Identifier: "pad"}}, + SkipResults: 1, + }) + if err != nil { + t.Fatalf("expected error getting references: %s", err) + } + + expectedReferences := []ResolvedLocation{ + {Dump: testDump1, Path: "sub1/bar.go", Range: testRange2}, + {Dump: testDump1, Path: "sub1/baz.go", Range: testRange3}, + {Dump: testDump1, Path: "sub1/bonk.go", Range: testRange4}, + {Dump: testDump1, Path: "sub1/quux.go", Range: testRange5}, + } + if diff := cmp.Diff(expectedReferences, references); diff != "" { + t.Errorf("unexpected references (-want +got):\n%s", diff) + } + + expectedNewCursor := Cursor{ + Phase: "definition-monikers", + DumpID: 42, + Path: "main.go", + Monikers: []bundles.MonikerData{{Kind: "export", Scheme: "gomod", Identifier: "pad"}}, + SkipResults: 0, + } + if !hasNewCursor { + t.Errorf("expected new cursor") + } else if diff := cmp.Diff(expectedNewCursor, newCursor); diff != "" { + t.Errorf("unexpected new cursor (-want +got):\n%s", diff) + } + }) +} + +func TestHandleDefinitionMonikersCursor(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + mockBundleClient1 := mocks.NewMockBundleClient() + mockBundleClient2 := mocks.NewMockBundleClient() + + setMockDBGetDumpByID(t, mockDB, map[int]db.Dump{42: testDump1, 50: testDump2}) + setMockBundleManagerClientBundleClient(t, mockBundleManagerClient, map[int]bundles.BundleClient{42: mockBundleClient1, 50: mockBundleClient2}) + setMockBundleClientPackageInformation(t, mockBundleClient1, "main.go", "1234", testPackageInformation) + setMockDBGetPackage(t, mockDB, "gomod", "leftpad", "0.1.0", testDump2, true) + + rpr := &ReferencePageResolver{ + db: mockDB, + bundleManagerClient: mockBundleManagerClient, + repositoryID: 100, + commit: testCommit, + limit: 5, + } + + t.Run("partial results", func(t *testing.T) { + setMockBundleClientMonikerResults(t, mockBundleClient2, "reference", "gomod", "pad", 0, 5, []bundles.Location{ + {DumpID: 50, Path: "foo.go", Range: testRange1}, + {DumpID: 50, Path: "bar.go", Range: testRange2}, + {DumpID: 50, Path: "baz.go", Range: testRange3}, + {DumpID: 50, Path: "bonk.go", Range: testRange4}, + {DumpID: 50, Path: "quux.go", Range: testRange5}, + }, 10) + + references, newCursor, hasNewCursor, err := rpr.dispatchCursorHandler(context.Background(), Cursor{ + Phase: "definition-monikers", + DumpID: 42, + Path: "main.go", + Monikers: []bundles.MonikerData{{Kind: "import", Scheme: "gomod", Identifier: "pad", PackageInformationID: "1234"}}, + SkipResults: 0, + }) + if err != nil { + t.Fatalf("expected error getting references: %s", err) + } + + expectedReferences := []ResolvedLocation{ + {Dump: testDump2, Path: "sub2/foo.go", Range: testRange1}, + {Dump: testDump2, Path: "sub2/bar.go", Range: testRange2}, + {Dump: testDump2, Path: "sub2/baz.go", Range: testRange3}, + {Dump: testDump2, Path: "sub2/bonk.go", Range: testRange4}, + {Dump: testDump2, Path: "sub2/quux.go", Range: testRange5}, + } + if diff := cmp.Diff(references, expectedReferences); diff != "" { + t.Errorf("unexpected references (-want +got):\n%s", diff) + } + + expectedNewCursor := Cursor{ + Phase: "definition-monikers", + DumpID: 42, + Path: "main.go", + Monikers: []bundles.MonikerData{{Kind: "import", Scheme: "gomod", Identifier: "pad", PackageInformationID: "1234"}}, + SkipResults: 5, + } + if !hasNewCursor { + t.Errorf("expected new cursor") + } else if diff := cmp.Diff(expectedNewCursor, newCursor); diff != "" { + t.Errorf("unexpected new cursor (-want +got):\n%s", diff) + } + }) + + t.Run("end of result set", func(t *testing.T) { + setMockBundleClientMonikerResults(t, mockBundleClient2, "reference", "gomod", "pad", 5, 5, []bundles.Location{ + {DumpID: 50, Path: "foo.go", Range: testRange1}, + {DumpID: 50, Path: "bar.go", Range: testRange2}, + {DumpID: 50, Path: "baz.go", Range: testRange3}, + {DumpID: 50, Path: "bonk.go", Range: testRange4}, + {DumpID: 50, Path: "quux.go", Range: testRange5}, + }, 10) + + references, newCursor, hasNewCursor, err := rpr.dispatchCursorHandler(context.Background(), Cursor{ + Phase: "definition-monikers", + DumpID: 42, + Path: "main.go", + Monikers: []bundles.MonikerData{{Kind: "import", Scheme: "gomod", Identifier: "pad", PackageInformationID: "1234"}}, + SkipResults: 5, + }) + if err != nil { + t.Fatalf("expected error getting references: %s", err) + } + + expectedReferences := []ResolvedLocation{ + {Dump: testDump2, Path: "sub2/foo.go", Range: testRange1}, + {Dump: testDump2, Path: "sub2/bar.go", Range: testRange2}, + {Dump: testDump2, Path: "sub2/baz.go", Range: testRange3}, + {Dump: testDump2, Path: "sub2/bonk.go", Range: testRange4}, + {Dump: testDump2, Path: "sub2/quux.go", Range: testRange5}, + } + if diff := cmp.Diff(expectedReferences, references); diff != "" { + t.Errorf("unexpected references (-want +got):\n%s", diff) + } + + expectedNewCursor := Cursor{ + Phase: "same-repo", + DumpID: 42, + Scheme: "gomod", + Identifier: "pad", + Name: "leftpad", + Version: "0.1.0", + } + if !hasNewCursor { + t.Errorf("expected new cursor") + } else if diff := cmp.Diff(expectedNewCursor, newCursor); diff != "" { + t.Errorf("unexpected new cursor (-want +got):\n%s", diff) + } + }) +} + +func TestHandleSameRepoCursor(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + mockBundleClient1 := mocks.NewMockBundleClient() + mockBundleClient2 := mocks.NewMockBundleClient() + mockBundleClient3 := mocks.NewMockBundleClient() + mockReferencePager := mocks.NewMockReferencePager() + + setMockDBGetDumpByID(t, mockDB, map[int]db.Dump{42: testDump1, 50: testDump2, 51: testDump3, 52: testDump4}) + setMockBundleManagerClientBundleClient(t, mockBundleManagerClient, map[int]bundles.BundleClient{50: mockBundleClient1, 51: mockBundleClient2, 52: mockBundleClient3}) + setMockDBSameRepoPager(t, mockDB, 100, testCommit, "gomod", "leftpad", "0.1.0", 5, 3, mockReferencePager) + setMockReferencePagerPageFromOffset(t, mockReferencePager, 0, []db.Reference{ + {DumpID: 50, Filter: readTestFilter(t, "normal", "1")}, + {DumpID: 51, Filter: readTestFilter(t, "normal", "1")}, + {DumpID: 52, Filter: readTestFilter(t, "normal", "1")}, + }) + + t.Run("partial results", func(t *testing.T) { + setMockBundleClientMonikerResults(t, mockBundleClient1, "reference", "gomod", "bar", 0, 5, []bundles.Location{ + {DumpID: 50, Path: "foo.go", Range: testRange1}, + {DumpID: 50, Path: "bar.go", Range: testRange2}, + {DumpID: 51, Path: "baz.go", Range: testRange3}, + {DumpID: 51, Path: "bonk.go", Range: testRange4}, + {DumpID: 52, Path: "quux.go", Range: testRange5}, + }, 10) + + rpr := &ReferencePageResolver{ + db: mockDB, + bundleManagerClient: mockBundleManagerClient, + repositoryID: 100, + commit: testCommit, + remoteDumpLimit: 5, + limit: 5, + } + + references, newCursor, hasNewCursor, err := rpr.resolvePage(context.Background(), Cursor{ + Phase: "same-repo", + DumpID: 42, + Scheme: "gomod", + Identifier: "bar", + Name: "leftpad", + Version: "0.1.0", + }) + if err != nil { + t.Fatalf("expected error getting references: %s", err) + } + + expectedReferences := []ResolvedLocation{ + {Dump: testDump2, Path: "sub2/foo.go", Range: testRange1}, + {Dump: testDump2, Path: "sub2/bar.go", Range: testRange2}, + {Dump: testDump2, Path: "sub2/baz.go", Range: testRange3}, + {Dump: testDump2, Path: "sub2/bonk.go", Range: testRange4}, + {Dump: testDump2, Path: "sub2/quux.go", Range: testRange5}, + } + if diff := cmp.Diff(expectedReferences, references); diff != "" { + t.Errorf("unexpected references (-want +got):\n%s", diff) + } + + expectedNewCursor := Cursor{ + Phase: "same-repo", + DumpID: 42, + Scheme: "gomod", + Identifier: "bar", + Name: "leftpad", + Version: "0.1.0", + DumpIDs: []int{50, 51, 52}, + TotalDumpsWhenBatching: 3, + SkipDumpsWhenBatching: 3, + SkipDumpsInBatch: 0, + SkipResultsInDump: 5, + } + if !hasNewCursor { + t.Errorf("expected new cursor") + } else if diff := cmp.Diff(expectedNewCursor, newCursor); diff != "" { + t.Errorf("unexpected new cursor (-want +got):\n%s", diff) + } + }) + + t.Run("multiple pages", func(t *testing.T) { + setMockBundleClientMonikerResults(t, mockBundleClient1, "reference", "gomod", "bar", 0, 5, []bundles.Location{ + {DumpID: 50, Path: "foo.go", Range: testRange1}, + {DumpID: 50, Path: "bar.go", Range: testRange2}, + }, 2) + setMockBundleClientMonikerResults(t, mockBundleClient2, "reference", "gomod", "bar", 0, 3, []bundles.Location{ + {DumpID: 51, Path: "baz.go", Range: testRange3}, + {DumpID: 51, Path: "bonk.go", Range: testRange4}, + }, 2) + setMockBundleClientMonikerResults(t, mockBundleClient3, "reference", "gomod", "bar", 0, 1, []bundles.Location{ + {DumpID: 52, Path: "quux.go", Range: testRange5}, + }, 1) + + rpr := &ReferencePageResolver{ + db: mockDB, + bundleManagerClient: mockBundleManagerClient, + repositoryID: 100, + commit: testCommit, + remoteDumpLimit: 5, + limit: 5, + } + + references, newCursor, hasNewCursor, err := rpr.resolvePage(context.Background(), Cursor{ + Phase: "same-repo", + DumpID: 42, + Scheme: "gomod", + Identifier: "bar", + Name: "leftpad", + Version: "0.1.0", + }) + if err != nil { + t.Fatalf("expected error getting references: %s", err) + } + + expectedReferences := []ResolvedLocation{ + {Dump: testDump2, Path: "sub2/foo.go", Range: testRange1}, + {Dump: testDump2, Path: "sub2/bar.go", Range: testRange2}, + {Dump: testDump3, Path: "sub3/baz.go", Range: testRange3}, + {Dump: testDump3, Path: "sub3/bonk.go", Range: testRange4}, + {Dump: testDump4, Path: "sub4/quux.go", Range: testRange5}, + } + if diff := cmp.Diff(expectedReferences, references); diff != "" { + t.Errorf("unexpected references (-want +got):\n%s", diff) + } + + expectedNewCursor := Cursor{ + Phase: "remote-repo", + DumpID: 42, + Scheme: "gomod", + Identifier: "bar", + Name: "leftpad", + Version: "0.1.0", + } + if !hasNewCursor { + t.Errorf("expected new cursor") + } else if diff := cmp.Diff(expectedNewCursor, newCursor); diff != "" { + t.Errorf("unexpected new cursor (-want +got):\n%s", diff) + } + }) +} + +func TestHandleSameRepoCursorMultipleDumpBatches(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + mockBundleClient := mocks.NewMockBundleClient() + mockReferencePager := mocks.NewMockReferencePager() + + setMockDBGetDumpByID(t, mockDB, map[int]db.Dump{42: testDump1, 50: testDump2, 51: testDump3, 52: testDump4}) + setMockBundleManagerClientBundleClient(t, mockBundleManagerClient, map[int]bundles.BundleClient{51: mockBundleClient}) + setMockDBSameRepoPager(t, mockDB, 100, testCommit, "gomod", "leftpad", "0.1.0", 2, 3, mockReferencePager) + setMockReferencePagerPageFromOffset(t, mockReferencePager, 0, []db.Reference{ + {DumpID: 50, Filter: readTestFilter(t, "normal", "1")}, + {DumpID: 51, Filter: readTestFilter(t, "normal", "1")}, + }) + setMockBundleClientMonikerResults(t, mockBundleClient, "reference", "gomod", "bar", 0, 5, []bundles.Location{ + {DumpID: 51, Path: "baz.go", Range: testRange3}, + {DumpID: 51, Path: "bonk.go", Range: testRange4}, + }, 2) + + rpr := &ReferencePageResolver{ + db: mockDB, + bundleManagerClient: mockBundleManagerClient, + repositoryID: 100, + commit: testCommit, + remoteDumpLimit: 2, + limit: 5, + } + + references, newCursor, hasNewCursor, err := rpr.dispatchCursorHandler(context.Background(), Cursor{ + Phase: "same-repo", + DumpID: 42, + Scheme: "gomod", + Identifier: "bar", + Name: "leftpad", + Version: "0.1.0", + DumpIDs: []int{50, 51}, + TotalDumpsWhenBatching: 3, + SkipDumpsWhenBatching: 2, + SkipDumpsInBatch: 1, + SkipResultsInDump: 0, + }) + if err != nil { + t.Fatalf("expected error getting references: %s", err) + } + + expectedReferences := []ResolvedLocation{ + {Dump: testDump3, Path: "sub3/baz.go", Range: testRange3}, + {Dump: testDump3, Path: "sub3/bonk.go", Range: testRange4}, + } + if diff := cmp.Diff(expectedReferences, references); diff != "" { + t.Errorf("unexpected references (-want +got):\n%s", diff) + } + + expectedNewCursor := Cursor{ + Phase: "same-repo", + DumpID: 42, + Scheme: "gomod", + Identifier: "bar", + Name: "leftpad", + Version: "0.1.0", + DumpIDs: []int{}, + TotalDumpsWhenBatching: 3, + SkipDumpsWhenBatching: 2, + SkipDumpsInBatch: 0, + SkipResultsInDump: 0, + } + if !hasNewCursor { + t.Errorf("expected new cursor") + } else if diff := cmp.Diff(expectedNewCursor, newCursor); diff != "" { + t.Errorf("unexpected new cursor (-want +got):\n%s", diff) + } +} + +// +// +// +// + +func TestHandleRemoteRepoCursor(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + mockBundleClient1 := mocks.NewMockBundleClient() + mockBundleClient2 := mocks.NewMockBundleClient() + mockBundleClient3 := mocks.NewMockBundleClient() + mockReferencePager := mocks.NewMockReferencePager() + + setMockDBGetDumpByID(t, mockDB, map[int]db.Dump{42: testDump1, 50: testDump2, 51: testDump3, 52: testDump4}) + setMockBundleManagerClientBundleClient(t, mockBundleManagerClient, map[int]bundles.BundleClient{50: mockBundleClient1, 51: mockBundleClient2, 52: mockBundleClient3}) + setMockDBPackageReferencePager(t, mockDB, "gomod", "leftpad", "0.1.0", 100, 5, 3, mockReferencePager) + setMockReferencePagerPageFromOffset(t, mockReferencePager, 0, []db.Reference{ + {DumpID: 50, Filter: readTestFilter(t, "normal", "1")}, + {DumpID: 51, Filter: readTestFilter(t, "normal", "1")}, + {DumpID: 52, Filter: readTestFilter(t, "normal", "1")}, + }) + + t.Run("partial results", func(t *testing.T) { + setMockBundleClientMonikerResults(t, mockBundleClient1, "reference", "gomod", "bar", 0, 5, []bundles.Location{ + {DumpID: 50, Path: "foo.go", Range: testRange1}, + {DumpID: 50, Path: "bar.go", Range: testRange2}, + {DumpID: 51, Path: "baz.go", Range: testRange3}, + {DumpID: 51, Path: "bonk.go", Range: testRange4}, + {DumpID: 52, Path: "quux.go", Range: testRange5}, + }, 10) + + rpr := &ReferencePageResolver{ + db: mockDB, + bundleManagerClient: mockBundleManagerClient, + repositoryID: 100, + commit: testCommit, + remoteDumpLimit: 5, + limit: 5, + } + + references, newCursor, hasNewCursor, err := rpr.resolvePage(context.Background(), Cursor{ + Phase: "remote-repo", + DumpID: 42, + Scheme: "gomod", + Identifier: "bar", + Name: "leftpad", + Version: "0.1.0", + }) + if err != nil { + t.Fatalf("expected error getting references: %s", err) + } + + expectedReferences := []ResolvedLocation{ + {Dump: testDump2, Path: "sub2/foo.go", Range: testRange1}, + {Dump: testDump2, Path: "sub2/bar.go", Range: testRange2}, + {Dump: testDump2, Path: "sub2/baz.go", Range: testRange3}, + {Dump: testDump2, Path: "sub2/bonk.go", Range: testRange4}, + {Dump: testDump2, Path: "sub2/quux.go", Range: testRange5}, + } + if diff := cmp.Diff(expectedReferences, references); diff != "" { + t.Errorf("unexpected references (-want +got):\n%s", diff) + } + + expectedNewCursor := Cursor{ + Phase: "remote-repo", + DumpID: 42, + Scheme: "gomod", + Identifier: "bar", + Name: "leftpad", + Version: "0.1.0", + DumpIDs: []int{50, 51, 52}, + TotalDumpsWhenBatching: 3, + SkipDumpsWhenBatching: 3, + SkipDumpsInBatch: 0, + SkipResultsInDump: 5, + } + if !hasNewCursor { + t.Errorf("expected new cursor") + } else if diff := cmp.Diff(expectedNewCursor, newCursor); diff != "" { + t.Errorf("unexpected new cursor (-want +got):\n%s", diff) + } + }) + + t.Run("multiple pages", func(t *testing.T) { + setMockBundleClientMonikerResults(t, mockBundleClient1, "reference", "gomod", "bar", 0, 5, []bundles.Location{ + {DumpID: 50, Path: "foo.go", Range: testRange1}, + {DumpID: 50, Path: "bar.go", Range: testRange2}, + }, 2) + setMockBundleClientMonikerResults(t, mockBundleClient2, "reference", "gomod", "bar", 0, 3, []bundles.Location{ + {DumpID: 51, Path: "baz.go", Range: testRange3}, + {DumpID: 51, Path: "bonk.go", Range: testRange4}, + }, 2) + setMockBundleClientMonikerResults(t, mockBundleClient3, "reference", "gomod", "bar", 0, 1, []bundles.Location{ + {DumpID: 52, Path: "quux.go", Range: testRange5}, + }, 1) + + rpr := &ReferencePageResolver{ + db: mockDB, + bundleManagerClient: mockBundleManagerClient, + repositoryID: 100, + commit: testCommit, + remoteDumpLimit: 5, + limit: 5, + } + + references, _, hasNewCursor, err := rpr.resolvePage(context.Background(), Cursor{ + Phase: "remote-repo", + DumpID: 42, + Scheme: "gomod", + Identifier: "bar", + Name: "leftpad", + Version: "0.1.0", + }) + if err != nil { + t.Fatalf("expected error getting references: %s", err) + } + + expectedReferences := []ResolvedLocation{ + {Dump: testDump2, Path: "sub2/foo.go", Range: testRange1}, + {Dump: testDump2, Path: "sub2/bar.go", Range: testRange2}, + {Dump: testDump3, Path: "sub3/baz.go", Range: testRange3}, + {Dump: testDump3, Path: "sub3/bonk.go", Range: testRange4}, + {Dump: testDump4, Path: "sub4/quux.go", Range: testRange5}, + } + if diff := cmp.Diff(expectedReferences, references); diff != "" { + t.Errorf("unexpected references (-want +got):\n%s", diff) + } + if hasNewCursor { + t.Errorf("unexpected new cursor") + } + }) +} + +func TestHandleRemoteRepoCursorMultipleDumpBatches(t *testing.T) { + mockDB := mocks.NewMockDB() + mockBundleManagerClient := mocks.NewMockBundleManagerClient() + mockBundleClient := mocks.NewMockBundleClient() + mockReferencePager := mocks.NewMockReferencePager() + + setMockDBGetDumpByID(t, mockDB, map[int]db.Dump{42: testDump1, 50: testDump2, 51: testDump3, 52: testDump4}) + setMockBundleManagerClientBundleClient(t, mockBundleManagerClient, map[int]bundles.BundleClient{51: mockBundleClient}) + setMockDBPackageReferencePager(t, mockDB, "gomod", "leftpad", "0.1.0", 100, 2, 3, mockReferencePager) + setMockReferencePagerPageFromOffset(t, mockReferencePager, 0, []db.Reference{ + {DumpID: 50, Filter: readTestFilter(t, "normal", "1")}, + {DumpID: 51, Filter: readTestFilter(t, "normal", "1")}, + }) + setMockBundleClientMonikerResults(t, mockBundleClient, "reference", "gomod", "bar", 0, 5, []bundles.Location{ + {DumpID: 51, Path: "baz.go", Range: testRange3}, + {DumpID: 51, Path: "bonk.go", Range: testRange4}, + }, 2) + + rpr := &ReferencePageResolver{ + db: mockDB, + bundleManagerClient: mockBundleManagerClient, + repositoryID: 100, + commit: testCommit, + remoteDumpLimit: 2, + limit: 5, + } + + references, newCursor, hasNewCursor, err := rpr.dispatchCursorHandler(context.Background(), Cursor{ + Phase: "remote-repo", + DumpID: 42, + Scheme: "gomod", + Identifier: "bar", + Name: "leftpad", + Version: "0.1.0", + DumpIDs: []int{50, 51}, + TotalDumpsWhenBatching: 3, + SkipDumpsWhenBatching: 2, + SkipDumpsInBatch: 1, + SkipResultsInDump: 0, + }) + if err != nil { + t.Fatalf("expected error getting references: %s", err) + } + + expectedReferences := []ResolvedLocation{ + {Dump: testDump3, Path: "sub3/baz.go", Range: testRange3}, + {Dump: testDump3, Path: "sub3/bonk.go", Range: testRange4}, + } + if diff := cmp.Diff(expectedReferences, references); diff != "" { + t.Errorf("unexpected references (-want +got):\n%s", diff) + } + + expectedNewCursor := Cursor{ + Phase: "remote-repo", + DumpID: 42, + Scheme: "gomod", + Identifier: "bar", + Name: "leftpad", + Version: "0.1.0", + DumpIDs: []int{}, + TotalDumpsWhenBatching: 3, + SkipDumpsWhenBatching: 2, + SkipDumpsInBatch: 0, + SkipResultsInDump: 0, + } + if !hasNewCursor { + t.Errorf("expected new cursor") + } else if diff := cmp.Diff(expectedNewCursor, newCursor); diff != "" { + t.Errorf("unexpected new cursor (-want +got):\n%s", diff) + } +} + +func TestApplyBloomFilter(t *testing.T) { + references := []db.Reference{ + {DumpID: 1, Filter: readTestFilter(t, "normal", "1")}, // bar + {DumpID: 2, Filter: readTestFilter(t, "normal", "2")}, // no bar + {DumpID: 3, Filter: readTestFilter(t, "normal", "3")}, // bar + {DumpID: 4, Filter: readTestFilter(t, "normal", "4")}, // bar + {DumpID: 5, Filter: readTestFilter(t, "normal", "5")}, // no bar + {DumpID: 6, Filter: readTestFilter(t, "normal", "6")}, // bar + {DumpID: 7, Filter: readTestFilter(t, "normal", "7")}, // bar + {DumpID: 8, Filter: readTestFilter(t, "normal", "8")}, // no bar + {DumpID: 9, Filter: readTestFilter(t, "normal", "9")}, // bar + {DumpID: 10, Filter: readTestFilter(t, "normal", "10")}, // bar + {DumpID: 11, Filter: readTestFilter(t, "normal", "11")}, // no bar + {DumpID: 12, Filter: readTestFilter(t, "normal", "12")}, // bar + } + + testCases := []struct { + limit int + expectedScanned int + expectedDumpIDs []int + }{ + {1, 1, []int{1}}, + {2, 3, []int{1, 3}}, + {6, 9, []int{1, 3, 4, 6, 7, 9}}, + {7, 10, []int{1, 3, 4, 6, 7, 9, 10}}, + {8, 12, []int{1, 3, 4, 6, 7, 9, 10, 12}}, + {12, 12, []int{1, 3, 4, 6, 7, 9, 10, 12}}, + } + + for _, testCase := range testCases { + name := fmt.Sprintf("limit=%d", testCase.limit) + + t.Run(name, func(t *testing.T) { + filteredReferences, scanned := applyBloomFilter(references, "bar", testCase.limit) + if scanned != testCase.expectedScanned { + t.Errorf("unexpected scanned. want=%d have=%d", testCase.expectedScanned, scanned) + } + + var filteredDumpIDs []int + for _, reference := range filteredReferences { + filteredDumpIDs = append(filteredDumpIDs, reference.DumpID) + } + + if diff := cmp.Diff(testCase.expectedDumpIDs, filteredDumpIDs); diff != "" { + t.Errorf("unexpected filtered references ids (-want +got):\n%s", diff) + } + }) + } +} diff --git a/cmd/precise-code-intel-api-server/internal/bundles/bundle_client.go b/cmd/precise-code-intel-api-server/internal/bundles/bundle_client.go new file mode 100644 index 00000000000..115e70afafb --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/bundles/bundle_client.go @@ -0,0 +1,191 @@ +package bundles + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/url" +) + +// BundleClient is the interface to the precise-code-intel-bundle-manager service scoped to a particular dump. +type BundleClient interface { + // Exists determines if the given path exists in the dump. + Exists(ctx context.Context, path string) (bool, error) + + // Definitions retrieves a list of definition locations for the symbol under the given location. + Definitions(ctx context.Context, path string, line, character int) ([]Location, error) + + // Definitions retrieves a list of reference locations for the symbol under the given location. + References(ctx context.Context, path string, line, character int) ([]Location, error) + + // Hover retrieves the hover text for the symbol under the given location. + Hover(ctx context.Context, path string, line, character int) (string, Range, bool, error) + + // MonikersByPosition retrieves a list of monikers attached to the symbol under the given location. There may + // be multiple ranges enclosing this point. The returned monikers are partitioned such that inner ranges occur + // first in the result, and outer ranges occur later. + MonikersByPosition(ctx context.Context, path string, line, character int) ([][]MonikerData, error) + + // MonikerResults retrieves a page of locations attached to a moniker and a total count of such locations. + MonikerResults(ctx context.Context, modelType, scheme, identifier string, skip, take int) ([]Location, int, error) + + // PackageInformation retrieves package information data by its identifier. + PackageInformation(ctx context.Context, path, packageInformationID string) (PackageInformationData, error) +} + +type bundleClientImpl struct { + bundleManagerURL string + bundleID int +} + +var _ BundleClient = &bundleClientImpl{} + +// Exists determines if the given path exists in the dump. +func (c *bundleClientImpl) Exists(ctx context.Context, path string) (exists bool, err error) { + err = c.request(ctx, "exists", map[string]interface{}{"path": path}, &exists) + return exists, err +} + +// Definitions retrieves a list of definition locations for the symbol under the given location. +func (c *bundleClientImpl) Definitions(ctx context.Context, path string, line, character int) (locations []Location, err error) { + args := map[string]interface{}{ + "path": path, + "line": line, + "character": character, + } + + err = c.request(ctx, "definitions", args, &locations) + c.addBundleIDToLocations(locations) + return locations, err +} + +// Definitions retrieves a list of reference locations for the symbol under the given location. +func (c *bundleClientImpl) References(ctx context.Context, path string, line, character int) (locations []Location, err error) { + args := map[string]interface{}{ + "path": path, + "line": line, + "character": character, + } + + err = c.request(ctx, "references", args, &locations) + c.addBundleIDToLocations(locations) + return locations, err +} + +// Hover retrieves the hover text for the symbol under the given location. +func (c *bundleClientImpl) Hover(ctx context.Context, path string, line, character int) (string, Range, bool, error) { + args := map[string]interface{}{ + "path": path, + "line": line, + "character": character, + } + + var target *json.RawMessage + if err := c.request(ctx, "hover", args, &target); err != nil { + return "", Range{}, false, err + } + + if target == nil { + return "", Range{}, false, nil + } + + payload := struct { + Text string `json:"text"` + Range Range `json:"range"` + }{} + + if err := json.Unmarshal(*target, &payload); err != nil { + return "", Range{}, false, err + } + + return payload.Text, payload.Range, true, nil +} + +// MonikersByPosition retrieves a list of monikers attached to the symbol under the given location. There may +// be multiple ranges enclosing this point. The returned monikers are partitioned such that inner ranges occur +// first in the result, and outer ranges occur later. +func (c *bundleClientImpl) MonikersByPosition(ctx context.Context, path string, line, character int) (target [][]MonikerData, err error) { + args := map[string]interface{}{ + "path": path, + "line": line, + "character": character, + } + + err = c.request(ctx, "monikersByPosition", args, &target) + return target, err +} + +// MonikerResults retrieves a page of locations attached to a moniker and a total count of such locations. +func (c *bundleClientImpl) MonikerResults(ctx context.Context, modelType, scheme, identifier string, skip, take int) (locations []Location, count int, err error) { + args := map[string]interface{}{ + "modelType": modelType, + "scheme": scheme, + "identifier": identifier, + } + if skip != 0 { + args["skip"] = skip + } + if take != 0 { + args["take"] = take + } + + target := struct { + Locations []Location `json:"locations"` + Count int `json:"count"` + }{} + + err = c.request(ctx, "monikerResults", args, &target) + locations = target.Locations + count = target.Count + c.addBundleIDToLocations(locations) + return locations, count, err +} + +// PackageInformation retrieves package information data by its identifier. +func (c *bundleClientImpl) PackageInformation(ctx context.Context, path, packageInformationID string) (target PackageInformationData, err error) { + args := map[string]interface{}{ + "path": path, + "packageInformationId": packageInformationID, + } + + err = c.request(ctx, "packageInformation", args, &target) + return target, err +} + +func (c *bundleClientImpl) request(ctx context.Context, path string, qs map[string]interface{}, target interface{}) error { + values := url.Values{} + for k, v := range qs { + values[k] = []string{fmt.Sprintf("%v", v)} + } + + url, err := url.Parse(fmt.Sprintf("%s/dbs/%d/%s", c.bundleManagerURL, c.bundleID, path)) + if err != nil { + return err + } + url.RawQuery = values.Encode() + + req, err := http.NewRequest("GET", url.String(), nil) + if err != nil { + return err + } + + // TODO - use context + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("unexpected status %d", resp.StatusCode) + } + + return json.NewDecoder(resp.Body).Decode(&target) +} + +func (c *bundleClientImpl) addBundleIDToLocations(locations []Location) { + for i := range locations { + locations[i].DumpID = c.bundleID + } +} diff --git a/cmd/precise-code-intel-api-server/internal/bundles/bundle_client_test.go b/cmd/precise-code-intel-api-server/internal/bundles/bundle_client_test.go new file mode 100644 index 00000000000..9f9f35cf817 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/bundles/bundle_client_test.go @@ -0,0 +1,292 @@ +package bundles + +import ( + "context" + "net/http" + "net/http/httptest" + "net/url" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestExists(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assertRequest(t, r, "GET", "/dbs/42/exists", map[string]string{ + "path": "main.go", + }) + + _, _ = w.Write([]byte(`true`)) + })) + defer ts.Close() + + client := &bundleClientImpl{bundleManagerURL: ts.URL, bundleID: 42} + exists, err := client.Exists(context.Background(), "main.go") + if err != nil { + t.Fatalf("unexpected error querying exists: %s", err) + } else if !exists { + t.Errorf("unexpected path to exist") + } +} + +func TestExistsBadResponse(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + })) + defer ts.Close() + + client := &bundleClientImpl{bundleManagerURL: ts.URL, bundleID: 42} + _, err := client.Exists(context.Background(), "main.go") + if err == nil { + t.Fatalf("unexpected nil error querying exists") + } +} + +func TestDefinitions(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assertRequest(t, r, "GET", "/dbs/42/definitions", map[string]string{ + "path": "main.go", + "line": "10", + "character": "20", + }) + + _, _ = w.Write([]byte(`[ + {"path": "foo.go", "range": {"start": {"line": 1, "character": 2}, "end": {"line": 3, "character": 4}}}, + {"path": "bar.go", "range": {"start": {"line": 5, "character": 6}, "end": {"line": 7, "character": 8}}} + ]`)) + })) + defer ts.Close() + + expected := []Location{ + {DumpID: 42, Path: "foo.go", Range: Range{Start: Position{1, 2}, End: Position{3, 4}}}, + {DumpID: 42, Path: "bar.go", Range: Range{Start: Position{5, 6}, End: Position{7, 8}}}, + } + + client := &bundleClientImpl{bundleManagerURL: ts.URL, bundleID: 42} + definitions, err := client.Definitions(context.Background(), "main.go", 10, 20) + if err != nil { + t.Fatalf("unexpected error querying definitions: %s", err) + } else if diff := cmp.Diff(expected, definitions); diff != "" { + t.Errorf("unexpected definitions (-want +got):\n%s", diff) + } +} + +func TestReferences(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assertRequest(t, r, "GET", "/dbs/42/references", map[string]string{ + "path": "main.go", + "line": "10", + "character": "20", + }) + + _, _ = w.Write([]byte(`[ + {"path": "foo.go", "range": {"start": {"line": 1, "character": 2}, "end": {"line": 3, "character": 4}}}, + {"path": "bar.go", "range": {"start": {"line": 5, "character": 6}, "end": {"line": 7, "character": 8}}} + ]`)) + })) + defer ts.Close() + + expected := []Location{ + {DumpID: 42, Path: "foo.go", Range: Range{Start: Position{1, 2}, End: Position{3, 4}}}, + {DumpID: 42, Path: "bar.go", Range: Range{Start: Position{5, 6}, End: Position{7, 8}}}, + } + + client := &bundleClientImpl{bundleManagerURL: ts.URL, bundleID: 42} + references, err := client.References(context.Background(), "main.go", 10, 20) + if err != nil { + t.Fatalf("unexpected error querying references: %s", err) + } else if diff := cmp.Diff(expected, references); diff != "" { + t.Errorf("unexpected references (-want +got):\n%s", diff) + } +} + +func TestHover(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assertRequest(t, r, "GET", "/dbs/42/hover", map[string]string{ + "path": "main.go", + "line": "10", + "character": "20", + }) + + _, _ = w.Write([]byte(`{ + "text": "starts the program", + "range": {"start": {"line": 1, "character": 2}, "end": {"line": 3, "character": 4}} + }`)) + })) + defer ts.Close() + + expectedText := "starts the program" + expectedRange := Range{ + Start: Position{1, 2}, + End: Position{3, 4}, + } + + client := &bundleClientImpl{bundleManagerURL: ts.URL, bundleID: 42} + text, r, exists, err := client.Hover(context.Background(), "main.go", 10, 20) + if err != nil { + t.Fatalf("unexpected error querying hover: %s", err) + } + + if !exists { + t.Errorf("expected hover text to exist") + } else { + if text != expectedText { + t.Errorf("unexpected hover text. want=%v have=%v", expectedText, text) + } else if diff := cmp.Diff(expectedRange, r); diff != "" { + t.Errorf("unexpected hover range (-want +got):\n%s", diff) + } + } +} + +func TestHoverNull(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assertRequest(t, r, "GET", "/dbs/42/hover", map[string]string{ + "path": "main.go", + "line": "10", + "character": "20", + }) + + _, _ = w.Write([]byte(`null`)) + })) + defer ts.Close() + + client := &bundleClientImpl{bundleManagerURL: ts.URL, bundleID: 42} + _, _, exists, err := client.Hover(context.Background(), "main.go", 10, 20) + if err != nil { + t.Fatalf("unexpected error querying hover: %s", err) + } else if exists { + t.Errorf("unexpected hover text") + } +} + +func TestMonikersByPosition(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assertRequest(t, r, "GET", "/dbs/42/monikersByPosition", map[string]string{ + "path": "main.go", + "line": "10", + "character": "20", + }) + + _, _ = w.Write([]byte(`[ + [{ + "kind": "import", + "scheme": "gomod", + "identifier": "pad1" + }], + [{ + "kind": "import", + "scheme": "gomod", + "identifier": "pad2", + "packageInformationID": "123" + }, { + "kind": "export", + "scheme": "gomod", + "identifier": "pad2", + "packageInformationID": "123" + }] + ]`)) + })) + defer ts.Close() + + expected := [][]MonikerData{ + { + {Kind: "import", Scheme: "gomod", Identifier: "pad1"}, + }, + { + {Kind: "import", Scheme: "gomod", Identifier: "pad2", PackageInformationID: "123"}, + {Kind: "export", Scheme: "gomod", Identifier: "pad2", PackageInformationID: "123"}, + }, + } + + client := &bundleClientImpl{bundleManagerURL: ts.URL, bundleID: 42} + monikers, err := client.MonikersByPosition(context.Background(), "main.go", 10, 20) + if err != nil { + t.Fatalf("unexpected error querying monikers by position: %s", err) + } else if diff := cmp.Diff(expected, monikers); diff != "" { + t.Errorf("unexpected moniker data (-want +got):\n%s", diff) + } +} + +func TestMonikerResults(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assertRequest(t, r, "GET", "/dbs/42/monikerResults", map[string]string{ + "modelType": "definitions", + "scheme": "gomod", + "identifier": "leftpad", + "take": "25", + }) + + _, _ = w.Write([]byte(`{ + "locations": [ + {"path": "foo.go", "range": {"start": {"line": 1, "character": 2}, "end": {"line": 3, "character": 4}}}, + {"path": "bar.go", "range": {"start": {"line": 5, "character": 6}, "end": {"line": 7, "character": 8}}} + ], + "count": 5 + }`)) + + })) + defer ts.Close() + + expected := []Location{ + {DumpID: 42, Path: "foo.go", Range: Range{Start: Position{1, 2}, End: Position{3, 4}}}, + {DumpID: 42, Path: "bar.go", Range: Range{Start: Position{5, 6}, End: Position{7, 8}}}, + } + + client := &bundleClientImpl{bundleManagerURL: ts.URL, bundleID: 42} + locations, count, err := client.MonikerResults(context.Background(), "definitions", "gomod", "leftpad", 0, 25) + if err != nil { + t.Fatalf("unexpected error querying moniker results: %s", err) + } + if count != 5 { + t.Errorf("unexpected count. want=%v have=%v", 2, count) + } + if diff := cmp.Diff(expected, locations); diff != "" { + t.Errorf("unexpected locations (-want +got):\n%s", diff) + } +} + +func TestPackageInformation(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assertRequest(t, r, "GET", "/dbs/42/packageInformation", map[string]string{ + "path": "main.go", + "packageInformationId": "123", + }) + + _, _ = w.Write([]byte(`{"name": "leftpad", "version": "0.1.0"}`)) + })) + defer ts.Close() + + expected := PackageInformationData{ + Name: "leftpad", + Version: "0.1.0", + } + + client := &bundleClientImpl{bundleManagerURL: ts.URL, bundleID: 42} + packageInformation, err := client.PackageInformation(context.Background(), "main.go", "123") + if err != nil { + t.Fatalf("unexpected error querying package information: %s", err) + } else if diff := cmp.Diff(expected, packageInformation); diff != "" { + t.Errorf("unexpected package information (-want +got):\n%s", diff) + } +} + +func assertRequest(t *testing.T, r *http.Request, expectedMethod, expectedPath string, expectedQuery map[string]string) { + if r.Method != expectedMethod { + t.Errorf("unexpected method. want=%s have=%s", expectedMethod, r.Method) + } + if r.URL.Path != expectedPath { + t.Errorf("unexpected path. want=%s have=%s", expectedPath, r.URL.Path) + } + if !compareQuery(r.URL.Query(), expectedQuery) { + t.Errorf("unexpected query. want=%v have=%s", expectedQuery, r.URL.Query().Encode()) + } +} + +func compareQuery(query url.Values, expected map[string]string) bool { + values := map[string]string{} + for k, v := range query { + values[k] = v[0] + } + + return cmp.Diff(expected, values) == "" +} diff --git a/cmd/precise-code-intel-api-server/internal/bundles/bundle_manager_client.go b/cmd/precise-code-intel-api-server/internal/bundles/bundle_manager_client.go new file mode 100644 index 00000000000..b968859440f --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/bundles/bundle_manager_client.go @@ -0,0 +1,61 @@ +package bundles + +import ( + "context" + "fmt" + "io" + "net/http" + "net/url" +) + +// BundleManagerClient is the interface to the precise-code-intel-bundle-manager service. +type BundleManagerClient interface { + // BundleClient creates a client that can answer intelligence queries for a single dump. + BundleClient(bundleID int) BundleClient + + // SendUpload transfers a raw LSIF upload to the bundle manager to be stored on disk. + SendUpload(ctx context.Context, bundleID int, r io.Reader) error +} + +type bundleManagerClientImpl struct { + bundleManagerURL string +} + +var _ BundleManagerClient = &bundleManagerClientImpl{} + +func New(bundleManagerURL string) BundleManagerClient { + return &bundleManagerClientImpl{bundleManagerURL: bundleManagerURL} +} + +// BundleClient creates a client that can answer intelligence queries for a single dump. +func (c *bundleManagerClientImpl) BundleClient(bundleID int) BundleClient { + return &bundleClientImpl{ + bundleManagerURL: c.bundleManagerURL, + bundleID: bundleID, + } +} + +// SendUpload transfers a raw LSIF upload to the bundle manager to be stored on disk. +func (c *bundleManagerClientImpl) SendUpload(ctx context.Context, bundleID int, r io.Reader) error { + url, err := url.Parse(fmt.Sprintf("%s/uploads/%d", c.bundleManagerURL, bundleID)) + if err != nil { + return err + } + + req, err := http.NewRequest("POST", url.String(), r) + if err != nil { + return err + } + + // TODO - use context + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("unexpected status %d", resp.StatusCode) + } + + return nil +} diff --git a/cmd/precise-code-intel-api-server/internal/bundles/bundle_manager_client_test.go b/cmd/precise-code-intel-api-server/internal/bundles/bundle_manager_client_test.go new file mode 100644 index 00000000000..af229ee0531 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/bundles/bundle_manager_client_test.go @@ -0,0 +1,49 @@ +package bundles + +import ( + "bytes" + "context" + "io/ioutil" + "net/http" + "net/http/httptest" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestSendUpload(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Method != "POST" { + t.Errorf("unexpected method. want=%s have=%s", "POST", r.Method) + } + if r.URL.Path != "/uploads/42" { + t.Errorf("unexpected method. want=%s have=%s", "/uploads/42", r.URL.Path) + } + + if content, err := ioutil.ReadAll(r.Body); err != nil { + t.Fatalf("unexpected error reading payload: %s", err) + } else if diff := cmp.Diff([]byte("payload\n"), content); diff != "" { + t.Errorf("unexpected request payload (-want +got):\n%s", diff) + } + })) + defer ts.Close() + + client := &bundleManagerClientImpl{bundleManagerURL: ts.URL} + err := client.SendUpload(context.Background(), 42, bytes.NewReader([]byte("payload\n"))) + if err != nil { + t.Fatalf("unexpected error sending upload: %s", err) + } +} + +func TestSendUploadBadResponse(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + })) + defer ts.Close() + + client := &bundleManagerClientImpl{bundleManagerURL: ts.URL} + err := client.SendUpload(context.Background(), 42, bytes.NewReader([]byte("payload\n"))) + if err == nil { + t.Fatalf("unexpected nil error sending upload") + } +} diff --git a/cmd/precise-code-intel-api-server/internal/bundles/types.go b/cmd/precise-code-intel-api-server/internal/bundles/types.go new file mode 100644 index 00000000000..6fe0ead0cfc --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/bundles/types.go @@ -0,0 +1,34 @@ +package bundles + +// Location is an LSP-like location scoped to a dump. +type Location struct { + DumpID int `json:"dumpId"` + Path string `json:"path"` + Range Range `json:"range"` +} + +// Range is an inclusive bounds within a file. +type Range struct { + Start Position `json:"start"` + End Position `json:"end"` +} + +// Position is a unique position within a file. +type Position struct { + Line int `json:"line"` + Character int `json:"character"` +} + +// MonikerData describes a moniker within a dump. +type MonikerData struct { + Kind string `json:"kind"` + Scheme string `json:"scheme"` + Identifier string `json:"identifier"` + PackageInformationID string `json:"packageInformationID"` +} + +// PackageInformationData describes a package within a package manager system. +type PackageInformationData struct { + Name string `json:"name"` + Version string `json:"version"` +} diff --git a/cmd/precise-code-intel-api-server/internal/db/ctes.go b/cmd/precise-code-intel-api-server/internal/db/ctes.go new file mode 100644 index 00000000000..a2f0cc62699 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/db/ctes.go @@ -0,0 +1,88 @@ +package db + +import ( + "fmt" + + "github.com/keegancsmith/sqlf" +) + +// MaxTraversalLimit is the maximum size of the CTE result set when traversing commit ancestor +// and descendants. This value affects how stale an upload can be while still serving code +// intelligence for a nearby commit. +const MaxTraversalLimit = 100 + +// visibleIDsCTE defines a CTE `visible_ids` that returns an ordered list of dump identifiers +// given a previously defined CTE `lineage`. The dump identifiers returned exclude the dumps +// shadowed by another dump: one dump shadows another when it has the same indexer value, has +// a root value enclosing the other, and when it is at a commit closer to the target commit +// value. +var visibleIDsCTE = ` + -- Limit the visibility to the maximum traversal depth and approximate + -- each commit's depth by its row number. + limited_lineage AS ( + SELECT a.*, row_number() OVER() as n from lineage a LIMIT ` + fmt.Sprintf("%d", MaxTraversalLimit) + ` + ), + -- Correlate commits to dumps and filter out commits without LSIF data + lineage_with_dumps AS ( + SELECT a.*, d.root, d.indexer, d.id as dump_id FROM limited_lineage a + JOIN lsif_dumps d ON d.repository_id = a.repository_id AND d."commit" = a."commit" + ), + visible_ids AS ( + -- Remove dumps where there exists another visible dump of smaller depth with an + -- overlapping root from the same indexer. Such dumps would not be returned with + -- a closest commit query so we don't want to return results for them in global + -- find-reference queries either. + SELECT DISTINCT t1.dump_id as id FROM lineage_with_dumps t1 WHERE NOT EXISTS ( + SELECT 1 FROM lineage_with_dumps t2 + WHERE t2.n < t1.n AND t1.indexer = t2.indexer AND ( + t2.root LIKE (t1.root || '%%%%') OR + t1.root LIKE (t2.root || '%%%%') + ) + ) + ) +` + +// withAncestorLineage prepares the given query by defining the CTE `visible_ids`. The set of +// candidate dumps are chosen by tracing the commit graph backwards (towards ancestors). +func withAncestorLineage(query string, repositoryID int, commit string, args ...interface{}) *sqlf.Query { + queryWithCTEs := ` + WITH + RECURSIVE lineage(id, "commit", parent, repository_id) AS ( + SELECT c.* FROM lsif_commits c WHERE c.repository_id = %s AND c."commit" = %s + UNION + SELECT c.* FROM lineage a JOIN lsif_commits c ON a.repository_id = c.repository_id AND a.parent = c."commit" + ), ` + visibleIDsCTE + " " + query + + return sqlf.Sprintf(queryWithCTEs, append([]interface{}{repositoryID, commit}, args...)...) +} + +// withBidirectionalLineage prepares the given query by defining the CTE `visible_ids`. The set of +// candidatedumps are chosen by tracing the commit graph both forwards and backwards. The resulting +// order of dumps are interleaved such that two dumps with a similar "distance" are near eachother +// in the result set. This prevents the resulting dumps from preferring one direction over the other. +func withBidirectionalLineage(query string, repositoryID int, commit string, args ...interface{}) *sqlf.Query { + queryWithCTEs := ` + WITH + RECURSIVE lineage(id, "commit", parent_commit, repository_id, direction) AS ( + SELECT l.* FROM ( + -- seed recursive set with commit looking in ancestor direction + SELECT c.*, 'A' FROM lsif_commits c WHERE c.repository_id = %s AND c."commit" = %s + UNION + -- seed recursive set with commit looking in descendant direction + SELECT c.*, 'D' FROM lsif_commits c WHERE c.repository_id = %s AND c."commit" = %s + ) l + + UNION + + SELECT * FROM ( + WITH l_inner AS (SELECT * FROM lineage) + -- get next ancestors (multiple parents for merge commits) + SELECT c.*, 'A' FROM l_inner l JOIN lsif_commits c ON l.direction = 'A' AND c.repository_id = l.repository_id AND c."commit" = l.parent_commit + UNION + -- get next descendants + SELECT c.*, 'D' FROM l_inner l JOIN lsif_commits c ON l.direction = 'D' and c.repository_id = l.repository_id AND c.parent_commit = l."commit" + ) subquery + ), ` + visibleIDsCTE + " " + query + + return sqlf.Sprintf(queryWithCTEs, append([]interface{}{repositoryID, commit, repositoryID, commit}, args...)...) +} diff --git a/cmd/precise-code-intel-api-server/internal/db/db.go b/cmd/precise-code-intel-api-server/internal/db/db.go new file mode 100644 index 00000000000..0dea5aa69e4 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/db/db.go @@ -0,0 +1,99 @@ +package db + +import ( + "context" + "database/sql" + "time" + + "github.com/keegancsmith/sqlf" + "github.com/sourcegraph/sourcegraph/internal/db/dbutil" +) + +// DB is the interface to Postgres that deals with LSIF-specific tables. +// +// - lsif_commits +// - lsif_packages +// - lsif_references +// - lsif_uploads +// +// These tables are kept separate from the remainder of Sourcegraph tablespace. +type DB interface { + // GetUploadByID returns an upload by its identifier and boolean flag indicating its existence. + GetUploadByID(ctx context.Context, id int) (Upload, bool, error) + + // GetUploadsByRepo returns a list of uploads for a particular repo and the total count of records matching the given conditions. + GetUploadsByRepo(ctx context.Context, repositoryID int, state, term string, visibleAtTip bool, limit, offset int) ([]Upload, int, error) + + // Enqueue inserts a new upload with a "queued" state, returning its identifier and a TxCloser that must be closed to commit the transaction. + Enqueue(ctx context.Context, commit, root, tracingContext string, repositoryID int, indexerName string) (int, TxCloser, error) + + // GetStates returns the states for the uploads with the given identifiers. + GetStates(ctx context.Context, ids []int) (map[int]string, error) + + // DeleteUploadByID deletes an upload by its identifier. If the upload was visible at the tip of its repository's default branch, + // the visibility of all uploads for that repository are recalculated. The given function is expected to return the newest commit + // on the default branch when invoked. + DeleteUploadByID(ctx context.Context, id int, getTipCommit func(repositoryID int) (string, error)) (bool, error) + + // ResetStalled moves all unlocked uploads processing for more than `StalledUploadMaxAge` back to the queued state. + // This method returns a list of updated upload identifiers. + ResetStalled(ctx context.Context, now time.Time) ([]int, error) + + // GetDumpByID returns a dump by its identifier and boolean flag indicating its existence. + GetDumpByID(ctx context.Context, id int) (Dump, bool, error) + + // FindClosestDumps returns the set of dumps that can most accurately answer queries for the given repository, commit, and file. + FindClosestDumps(ctx context.Context, repositoryID int, commit, file string) ([]Dump, error) + + // DeleteOldestDump deletes the oldest dump that is not currently visible at the tip of its repository's default branch. + // This method returns the deleted dump's identifier and a flag indicating its (previous) existence. + DeleteOldestDump(ctx context.Context) (int, bool, error) + + // GetPackage returns the dump that provides the package with the given scheme, name, and version and a flag indicating its existence. + GetPackage(ctx context.Context, scheme, name, version string) (Dump, bool, error) + + // SameRepoPager returns a ReferencePager for dumps that belong to the given repository and commit and reference the package with the + // given scheme, name, and version. + SameRepoPager(ctx context.Context, repositoryID int, commit, scheme, name, version string, limit int) (int, ReferencePager, error) + + // PackageReferencePager returns a ReferencePager for dumps that belong to a remote repository (distinct from the given repository id) + // and reference the package with the given scheme, name, and version. All resulting dumps are visible at the tip of their repository's + // default branch. + PackageReferencePager(ctx context.Context, scheme, name, version string, repositoryID, limit int) (int, ReferencePager, error) +} + +type dbImpl struct { + db *sql.DB +} + +var _ DB = &dbImpl{} + +// New creates a new instance of DB connected to the given Postgres DSN. +func New(postgresDSN string) (DB, error) { + db, err := dbutil.NewDB(postgresDSN, "precise-code-intel-api-server") + if err != nil { + return nil, err + } + + return &dbImpl{db: db}, nil +} + +// query performs Query on the underlying connection. +func (db *dbImpl) query(ctx context.Context, query *sqlf.Query) (*sql.Rows, error) { + return db.db.QueryContext(ctx, query.Query(sqlf.PostgresBindVar), query.Args()...) +} + +// queryRow performs QueryRow on the underlying connection. +func (db *dbImpl) queryRow(ctx context.Context, query *sqlf.Query) *sql.Row { + return db.db.QueryRowContext(ctx, query.Query(sqlf.PostgresBindVar), query.Args()...) +} + +// beginTx performs BeginTx on the underlying connection and wraps the transaction. +func (db *dbImpl) beginTx(ctx context.Context) (*transactionWrapper, error) { + tx, err := db.db.BeginTx(ctx, nil) + if err != nil { + return nil, err + } + + return &transactionWrapper{tx}, nil +} diff --git a/cmd/precise-code-intel-api-server/internal/db/db_test.go b/cmd/precise-code-intel-api-server/internal/db/db_test.go new file mode 100644 index 00000000000..c4dad4f6eb2 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/db/db_test.go @@ -0,0 +1,7 @@ +package db + +import "github.com/sourcegraph/sourcegraph/internal/db/dbtesting" + +func init() { + dbtesting.DBNameSuffix = "precise-code-intel-api-server" +} diff --git a/cmd/precise-code-intel-api-server/internal/db/dumps.go b/cmd/precise-code-intel-api-server/internal/db/dumps.go new file mode 100644 index 00000000000..2a054e0e6e4 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/db/dumps.go @@ -0,0 +1,168 @@ +package db + +import ( + "context" + "time" + + "github.com/keegancsmith/sqlf" +) + +// Dump is a subset of the lsif_uploads table (queried via the lsif_dumps view) and stores +// only processed records. +type Dump struct { + ID int `json:"id"` + Commit string `json:"commit"` + Root string `json:"root"` + VisibleAtTip bool `json:"visibleAtTip"` + UploadedAt time.Time `json:"uploadedAt"` + State string `json:"state"` + FailureSummary *string `json:"failureSummary"` + FailureStacktrace *string `json:"failureStacktrace"` + StartedAt *time.Time `json:"startedAt"` + FinishedAt *time.Time `json:"finishedAt"` + TracingContext string `json:"tracingContext"` + RepositoryID int `json:"repositoryId"` + Indexer string `json:"indexer"` +} + +// GetDumpByID returns a dump by its identifier and boolean flag indicating its existence. +func (db *dbImpl) GetDumpByID(ctx context.Context, id int) (Dump, bool, error) { + query := ` + SELECT + d.id, + d.commit, + d.root, + d.visible_at_tip, + d.uploaded_at, + d.state, + d.failure_summary, + d.failure_stacktrace, + d.started_at, + d.finished_at, + d.tracing_context, + d.repository_id, + d.indexer + FROM lsif_dumps d WHERE id = %d + ` + + dump, err := scanDump(db.queryRow(ctx, sqlf.Sprintf(query, id))) + if err != nil { + return Dump{}, false, ignoreErrNoRows(err) + } + + return dump, true, nil +} + +// FindClosestDumps returns the set of dumps that can most accurately answer queries for the given repository, commit, and file. +func (db *dbImpl) FindClosestDumps(ctx context.Context, repositoryID int, commit, file string) ([]Dump, error) { + tw, err := db.beginTx(ctx) + if err != nil { + return nil, err + } + defer func() { + err = closeTx(tw.tx, err) + }() + + visibleIDsQuery := ` + SELECT d.dump_id FROM lineage_with_dumps d + WHERE %s LIKE (d.root || '%%%%') AND d.dump_id IN (SELECT * FROM visible_ids) + ORDER BY d.n + ` + + ids, err := scanInts(tw.query(ctx, withBidirectionalLineage(visibleIDsQuery, repositoryID, commit, file))) + if err != nil { + return nil, err + } + + if len(ids) == 0 { + return nil, nil + } + + query := ` + SELECT + d.id, + d.commit, + d.root, + d.visible_at_tip, + d.uploaded_at, + d.state, + d.failure_summary, + d.failure_stacktrace, + d.started_at, + d.finished_at, + d.tracing_context, + d.repository_id, + d.indexer + FROM lsif_dumps d WHERE id IN (%s) + ` + + dumps, err := scanDumps(tw.query(ctx, sqlf.Sprintf(query, sqlf.Join(intsToQueries(ids), ", ")))) + if err != nil { + return nil, err + } + + return deduplicateDumps(dumps), nil + +} + +// deduplicateDumps returns a copy of the given slice of dumps with duplicate identifiers removed. +// The first dump with a unique identifier is retained. +func deduplicateDumps(allDumps []Dump) (dumps []Dump) { + dumpIDs := map[int]struct{}{} + for _, dump := range allDumps { + if _, ok := dumpIDs[dump.ID]; ok { + continue + } + + dumpIDs[dump.ID] = struct{}{} + dumps = append(dumps, dump) + } + + return dumps +} + +// DeleteOldestDump deletes the oldest dump that is not currently visible at the tip of its repository's default branch. +// This method returns the deleted dump's identifier and a flag indicating its (previous) existence. +func (db *dbImpl) DeleteOldestDump(ctx context.Context) (int, bool, error) { + query := ` + DELETE FROM lsif_uploads + WHERE id IN ( + SELECT id FROM lsif_dumps + WHERE visible_at_tip = false + ORDER BY uploaded_at + LIMIT 1 + ) RETURNING id + ` + + id, err := scanInt(db.queryRow(ctx, sqlf.Sprintf(query))) + if err != nil { + return 0, false, ignoreErrNoRows(err) + } + + return id, true, nil +} + +// updateDumpsVisibleFromTip recalculates the visible_at_tip flag of all dumps of the given repository. +func (db *dbImpl) updateDumpsVisibleFromTip(ctx context.Context, tw *transactionWrapper, repositoryID int, tipCommit string) (err error) { + if tw == nil { + tw, err = db.beginTx(ctx) + if err != nil { + return err + } + defer func() { + err = closeTx(tw.tx, err) + }() + } + + // Update dump records by: + // (1) unsetting the visibility flag of all previously visible dumps, and + // (2) setting the visibility flag of all currently visible dumps + query := ` + UPDATE lsif_dumps d + SET visible_at_tip = id IN (SELECT * from visible_ids) + WHERE d.repository_id = %s AND (d.id IN (SELECT * from visible_ids) OR d.visible_at_tip) + ` + + _, err = tw.exec(ctx, withAncestorLineage(query, repositoryID, tipCommit, repositoryID)) + return err +} diff --git a/cmd/precise-code-intel-api-server/internal/db/dumps_test.go b/cmd/precise-code-intel-api-server/internal/db/dumps_test.go new file mode 100644 index 00000000000..8b3111855ad --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/db/dumps_test.go @@ -0,0 +1,590 @@ +package db + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/sourcegraph/sourcegraph/internal/db/dbconn" + "github.com/sourcegraph/sourcegraph/internal/db/dbtesting" +) + +func TestGetDumpByID(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + // Dump does not exist initially + if _, exists, err := db.GetDumpByID(context.Background(), 1); err != nil { + t.Fatalf("unexpected error getting dump: %s", err) + } else if exists { + t.Fatal("unexpected record") + } + + uploadedAt := time.Unix(1587396557, 0).UTC() + startedAt := uploadedAt.Add(time.Minute) + finishedAt := uploadedAt.Add(time.Minute * 2) + expected := Dump{ + ID: 1, + Commit: makeCommit(1), + Root: "sub/", + VisibleAtTip: true, + UploadedAt: uploadedAt, + State: "completed", + FailureSummary: nil, + FailureStacktrace: nil, + StartedAt: &startedAt, + FinishedAt: &finishedAt, + TracingContext: `{"id": 42}`, + RepositoryID: 50, + Indexer: "lsif-go", + } + + insertUploads(t, db.db, Upload{ + ID: expected.ID, + Commit: expected.Commit, + Root: expected.Root, + VisibleAtTip: expected.VisibleAtTip, + UploadedAt: expected.UploadedAt, + State: expected.State, + FailureSummary: expected.FailureSummary, + FailureStacktrace: expected.FailureStacktrace, + StartedAt: expected.StartedAt, + FinishedAt: expected.FinishedAt, + TracingContext: expected.TracingContext, + RepositoryID: expected.RepositoryID, + Indexer: expected.Indexer, + }) + + if dump, exists, err := db.GetDumpByID(context.Background(), 1); err != nil { + t.Fatalf("unexpected error getting dump: %s", err) + } else if !exists { + t.Fatal("expected record to exist") + } else if diff := cmp.Diff(expected, dump); diff != "" { + t.Errorf("unexpected dump (-want +got):\n%s", diff) + } +} + +func TestFindClosestDumps(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + // This database has the following commit graph: + // + // [1] --+--- 2 --------+--5 -- 6 --+-- [7] + // | | | + // +-- [3] -- 4 --+ +--- 8 + + insertCommits(t, db.db, map[string][]string{ + makeCommit(1): {}, + makeCommit(2): {makeCommit(1)}, + makeCommit(3): {makeCommit(1)}, + makeCommit(4): {makeCommit(3)}, + makeCommit(5): {makeCommit(2), makeCommit(4)}, + makeCommit(6): {makeCommit(5)}, + makeCommit(7): {makeCommit(6)}, + makeCommit(8): {makeCommit(6)}, + }) + + insertUploads(t, db.db, + Upload{ID: 1, Commit: makeCommit(1)}, + Upload{ID: 2, Commit: makeCommit(3)}, + Upload{ID: 3, Commit: makeCommit(7)}, + ) + + testFindClosestDumps(t, db, []FindClosestDumpsTestCase{ + {commit: makeCommit(1), file: "file.ts", anyOfIDs: []int{1}}, + {commit: makeCommit(2), file: "file.ts", anyOfIDs: []int{1}}, + {commit: makeCommit(3), file: "file.ts", anyOfIDs: []int{2}}, + {commit: makeCommit(4), file: "file.ts", anyOfIDs: []int{2}}, + {commit: makeCommit(6), file: "file.ts", anyOfIDs: []int{3}}, + {commit: makeCommit(7), file: "file.ts", anyOfIDs: []int{3}}, + {commit: makeCommit(5), file: "file.ts", anyOfIDs: []int{1, 2, 3}}, + {commit: makeCommit(8), file: "file.ts", anyOfIDs: []int{1, 2}}, + }) +} + +func TestFindClosestDumpsAlternateCommitGraph(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + // This database has the following commit graph: + // + // 1 --+-- [2] ---- 3 + // | + // +--- 4 --+-- 5 -- 6 + // | + // +-- 7 -- 8 + + insertCommits(t, db.db, map[string][]string{ + makeCommit(1): {}, + makeCommit(2): {makeCommit(1)}, + makeCommit(3): {makeCommit(2)}, + makeCommit(4): {makeCommit(1)}, + makeCommit(5): {makeCommit(4)}, + makeCommit(6): {makeCommit(5)}, + makeCommit(7): {makeCommit(4)}, + makeCommit(8): {makeCommit(7)}, + }) + + insertUploads(t, db.db, + Upload{ID: 1, Commit: makeCommit(2)}, + ) + + testFindClosestDumps(t, db, []FindClosestDumpsTestCase{ + {commit: makeCommit(1), allOfIDs: []int{1}}, + {commit: makeCommit(2), allOfIDs: []int{1}}, + {commit: makeCommit(3), allOfIDs: []int{1}}, + {commit: makeCommit(4)}, + {commit: makeCommit(6)}, + {commit: makeCommit(7)}, + {commit: makeCommit(5)}, + {commit: makeCommit(8)}, + }) +} + +func TestFindClosestDumpsDistinctRoots(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + // This database has the following commit graph: + // + // 1 --+-- [2] + + insertCommits(t, db.db, map[string][]string{ + makeCommit(1): {}, + makeCommit(2): {makeCommit(1)}, + }) + + insertUploads(t, db.db, + Upload{ID: 1, Commit: makeCommit(2), Root: "root1/"}, + Upload{ID: 2, Commit: makeCommit(2), Root: "root2/"}, + ) + + testFindClosestDumps(t, db, []FindClosestDumpsTestCase{ + {commit: makeCommit(1), file: "blah"}, + {commit: makeCommit(2), file: "root1/file.ts", allOfIDs: []int{1}}, + {commit: makeCommit(1), file: "root2/file.ts", allOfIDs: []int{2}}, + {commit: makeCommit(2), file: "root2/file.ts", allOfIDs: []int{2}}, + {commit: makeCommit(1), file: "root3/file.ts"}, + }) +} + +func TestFindClosestDumpsOverlappingRoots(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + // This database has the following commit graph: + // + // 1 -- 2 --+-- 3 --+-- 5 -- 6 + // | | + // +-- 4 --+ + // + // With the following LSIF dumps: + // + // | Commit | Root | Indexer | + // | ------ + ------- + ------- | + // | 1 | root3/ | lsif-go | + // | 1 | root4/ | lsif-py | + // | 2 | root1/ | lsif-go | + // | 2 | root2/ | lsif-go | + // | 2 | | lsif-py | (overwrites root4/ at commit 1) + // | 3 | root1/ | lsif-go | (overwrites root1/ at commit 2) + // | 4 | | lsif-py | (overwrites (root) at commit 2) + // | 5 | root2/ | lsif-go | (overwrites root2/ at commit 2) + // | 6 | root1/ | lsif-go | (overwrites root1/ at commit 2) + + insertCommits(t, db.db, map[string][]string{ + makeCommit(1): {}, + makeCommit(2): {makeCommit(1)}, + makeCommit(3): {makeCommit(2)}, + makeCommit(4): {makeCommit(2)}, + makeCommit(5): {makeCommit(3), makeCommit(4)}, + makeCommit(6): {makeCommit(5)}, + }) + + insertUploads(t, db.db, + Upload{ID: 1, Commit: makeCommit(1), Root: "root3/"}, + Upload{ID: 2, Commit: makeCommit(1), Root: "root4/", Indexer: "lsif-py"}, + Upload{ID: 3, Commit: makeCommit(2), Root: "root1/"}, + Upload{ID: 4, Commit: makeCommit(2), Root: "root2/"}, + Upload{ID: 5, Commit: makeCommit(2), Root: "", Indexer: "lsif-py"}, + Upload{ID: 6, Commit: makeCommit(3), Root: "root1/"}, + Upload{ID: 7, Commit: makeCommit(4), Root: "", Indexer: "lsif-py"}, + Upload{ID: 8, Commit: makeCommit(5), Root: "root2/"}, + Upload{ID: 9, Commit: makeCommit(6), Root: "root1/"}, + ) + + testFindClosestDumps(t, db, []FindClosestDumpsTestCase{ + {commit: makeCommit(4), file: "root1/file.ts", allOfIDs: []int{7, 3}}, + {commit: makeCommit(5), file: "root2/file.ts", allOfIDs: []int{8, 7}}, + {commit: makeCommit(3), file: "root3/file.ts", allOfIDs: []int{5, 1}}, + {commit: makeCommit(1), file: "root4/file.ts", allOfIDs: []int{2}}, + {commit: makeCommit(2), file: "root4/file.ts", allOfIDs: []int{5}}, + }) +} + +func TestFindClosestDumpsMaxTraversalLimit(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + // This repository has the following commit graph (ancestors to the left): + // + // MAX_TRAVERSAL_LIMIT -- ... -- 2 -- 1 -- 0 + // + // At commit `50`, the traversal limit will be reached before visiting commit `0` + // because commits are visited in this order: + // + // | depth | commit | + // | ----- | ------ | + // | 1 | 50 | (with direction 'A') + // | 2 | 50 | (with direction 'D') + // | 3 | 51 | + // | 4 | 49 | + // | 5 | 52 | + // | 6 | 48 | + // | ... | | + // | 99 | 99 | + // | 100 | 1 | (limit reached) + + commits := map[string][]string{} + for i := 0; i < MaxTraversalLimit; i++ { + commits[makeCommit(i)] = []string{makeCommit(i + 1)} + } + + insertCommits(t, db.db, commits) + insertUploads(t, db.db, Upload{ID: 1, Commit: makeCommit(0)}) + + testFindClosestDumps(t, db, []FindClosestDumpsTestCase{ + {commit: makeCommit(0), file: "file.ts", allOfIDs: []int{1}}, + {commit: makeCommit(1), file: "file.ts", allOfIDs: []int{1}}, + {commit: makeCommit(MaxTraversalLimit/2 - 1), file: "file.ts", allOfIDs: []int{1}}, + {commit: makeCommit(MaxTraversalLimit / 2), file: "file.ts"}, + }) +} + +func TestDeleteOldestDump(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + // Cannot prune empty dump set + if _, prunable, err := db.DeleteOldestDump(context.Background()); err != nil { + t.Fatalf("unexpected error pruning dumps: %s", err) + } else if prunable { + t.Fatal("unexpectedly prunable") + } + + t1 := time.Unix(1587396557, 0).UTC() + t2 := t1.Add(time.Minute) + t3 := t1.Add(time.Minute * 2) + t4 := t1.Add(time.Minute * 3) + + insertUploads(t, db.db, + Upload{ID: 1, UploadedAt: t1}, + Upload{ID: 2, UploadedAt: t2, VisibleAtTip: true}, + Upload{ID: 3, UploadedAt: t3}, + Upload{ID: 4, UploadedAt: t4}, + ) + + // Prune oldest + if id, prunable, err := db.DeleteOldestDump(context.Background()); err != nil { + t.Fatalf("unexpected error pruning dumps: %s", err) + } else if !prunable { + t.Fatal("unexpectedly non-prunable") + } else if id != 1 { + t.Errorf("unexpected pruned identifier. want=%d have=%d", 1, id) + } + + // Prune next oldest (skips visible at tip) + if id, prunable, err := db.DeleteOldestDump(context.Background()); err != nil { + t.Fatalf("unexpected error pruning dumps: %s", err) + } else if !prunable { + t.Fatal("unexpectedly non-prunable") + } else if id != 3 { + t.Errorf("unexpected pruned identifier. want=%d have=%d", 3, id) + } +} + +type FindClosestDumpsTestCase struct { + commit string + file string + anyOfIDs []int + allOfIDs []int +} + +func testFindClosestDumps(t *testing.T, db DB, testCases []FindClosestDumpsTestCase) { + for _, testCase := range testCases { + name := fmt.Sprintf("commit=%s file=%s", testCase.commit, testCase.file) + + t.Run(name, func(t *testing.T) { + dumps, err := db.FindClosestDumps(context.Background(), 50, testCase.commit, testCase.file) + if err != nil { + t.Fatalf("unexpected error finding closest dumps: %s", err) + } + + if len(testCase.anyOfIDs) > 0 { + testAnyOf(t, dumps, testCase.anyOfIDs) + return + } + + if len(testCase.allOfIDs) > 0 { + testAllOf(t, dumps, testCase.allOfIDs) + return + } + + if len(dumps) != 0 { + t.Errorf("unexpected nearest dump length. want=%d have=%d", 0, len(dumps)) + return + } + }) + } +} + +func testAnyOf(t *testing.T, dumps []Dump, expectedIDs []int) { + if len(dumps) != 1 { + t.Errorf("unexpected nearest dump length. want=%d have=%d", 1, len(dumps)) + return + } + + if !testPresence(dumps[0].ID, expectedIDs) { + t.Errorf("unexpected nearest dump ids. want one of %v have=%v", expectedIDs, dumps[0].ID) + } +} + +func testAllOf(t *testing.T, dumps []Dump, expectedIDs []int) { + if len(dumps) != len(expectedIDs) { + t.Errorf("unexpected nearest dump length. want=%d have=%d", 1, len(dumps)) + } + + var dumpIDs []int + for _, dump := range dumps { + dumpIDs = append(dumpIDs, dump.ID) + } + + for _, expectedID := range expectedIDs { + if !testPresence(expectedID, dumpIDs) { + t.Errorf("unexpected nearest dump ids. want all of %v have=%v", expectedIDs, dumpIDs) + return + } + } + +} + +func testPresence(needle int, haystack []int) bool { + for _, candidate := range haystack { + if needle == candidate { + return true + } + } + + return false +} + +func TestUpdateDumpsVisibleFromTipOverlappingRootsSameIndexer(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + // This database has the following commit graph: + // + // [1] -- [2] -- [3] -- [4] -- 5 -- [6] -- [7] + + insertUploads(t, db.db, + Upload{ID: 1, Commit: makeCommit(1), Root: "r1/"}, + Upload{ID: 2, Commit: makeCommit(2), Root: "r2/"}, + Upload{ID: 3, Commit: makeCommit(3)}, + Upload{ID: 4, Commit: makeCommit(4), Root: "r3/"}, + Upload{ID: 5, Commit: makeCommit(6), Root: "r4/"}, + Upload{ID: 6, Commit: makeCommit(7), Root: "r5/"}, + ) + + insertCommits(t, db.db, map[string][]string{ + makeCommit(1): {}, + makeCommit(2): {makeCommit(1)}, + makeCommit(3): {makeCommit(2)}, + makeCommit(4): {makeCommit(3)}, + makeCommit(5): {makeCommit(4)}, + makeCommit(6): {makeCommit(5)}, + makeCommit(7): {makeCommit(6)}, + }) + + err := db.updateDumpsVisibleFromTip(context.Background(), nil, 50, makeCommit(6)) + if err != nil { + t.Fatalf("unexpected error updating dumps visible from tip: %s", err) + } + + visibilities := getDumpVisibilities(t, db.db) + expected := map[int]bool{1: false, 2: false, 3: false, 4: true, 5: true, 6: false} + + if diff := cmp.Diff(expected, visibilities); diff != "" { + t.Errorf("unexpected visibility (-want +got):\n%s", diff) + } +} + +func TestUpdateDumpsVisibleFromTipOverlappingRoots(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + // This database has the following commit graph: + // + // [1] -- 2 -- [3] -- [4] -- [5] -- [6] -- [7] + + insertUploads(t, db.db, + Upload{ID: 1, Commit: makeCommit(1), Root: "r1/"}, + Upload{ID: 2, Commit: makeCommit(3), Root: "r2/"}, + Upload{ID: 3, Commit: makeCommit(4), Root: "r1/"}, + Upload{ID: 4, Commit: makeCommit(6), Root: "r3/"}, + Upload{ID: 5, Commit: makeCommit(7), Root: "r4/"}, + Upload{ID: 6, Commit: makeCommit(1), Root: "r1/", Indexer: "lsif-tsc"}, + Upload{ID: 7, Commit: makeCommit(3), Root: "r2/", Indexer: "lsif-tsc"}, + Upload{ID: 8, Commit: makeCommit(4), Indexer: "lsif-tsc"}, + Upload{ID: 9, Commit: makeCommit(5), Root: "r3/", Indexer: "lsif-tsc"}, + ) + + insertCommits(t, db.db, map[string][]string{ + makeCommit(1): {}, + makeCommit(2): {makeCommit(1)}, + makeCommit(3): {makeCommit(2)}, + makeCommit(4): {makeCommit(3)}, + makeCommit(5): {makeCommit(4)}, + makeCommit(6): {makeCommit(5)}, + makeCommit(7): {makeCommit(6)}, + }) + + err := db.updateDumpsVisibleFromTip(context.Background(), nil, 50, makeCommit(6)) + if err != nil { + t.Fatalf("unexpected error updating dumps visible from tip: %s", err) + } + + visibilities := getDumpVisibilities(t, db.db) + expected := map[int]bool{1: false, 2: true, 3: true, 4: true, 5: false, 6: false, 7: false, 8: false, 9: true} + if diff := cmp.Diff(expected, visibilities); diff != "" { + t.Errorf("unexpected visibility. want=%v have=%v", expected, visibilities) + } +} + +func TestUpdateDumpsVisibleFromTipBranchingPaths(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + // This database has the following commit graph: + // + // 1 --+-- [2] --- 3 ---+ + // | | + // +--- 4 --- [5] --+ -- [8] --+-- [9] + // | | + // +-- [6] --- 7 --------------+ + + insertUploads(t, db.db, + Upload{ID: 1, Commit: makeCommit(2), Root: "r2/"}, + Upload{ID: 2, Commit: makeCommit(5), Root: "r2/a/"}, + Upload{ID: 3, Commit: makeCommit(5), Root: "r2/b/"}, + Upload{ID: 4, Commit: makeCommit(6), Root: "r1/a/"}, + Upload{ID: 5, Commit: makeCommit(6), Root: "r1/b/"}, + Upload{ID: 6, Commit: makeCommit(8), Root: "r1/"}, + Upload{ID: 7, Commit: makeCommit(9), Root: "r3/"}, + ) + + insertCommits(t, db.db, map[string][]string{ + makeCommit(1): {}, + makeCommit(2): {makeCommit(1)}, + makeCommit(3): {makeCommit(2)}, + makeCommit(4): {makeCommit(1)}, + makeCommit(5): {makeCommit(4)}, + makeCommit(8): {makeCommit(5), makeCommit(3)}, + makeCommit(9): {makeCommit(7), makeCommit(8)}, + makeCommit(6): {makeCommit(1)}, + makeCommit(7): {makeCommit(6)}, + }) + + err := db.updateDumpsVisibleFromTip(context.Background(), nil, 50, makeCommit(9)) + if err != nil { + t.Fatalf("unexpected error updating dumps visible from tip: %s", err) + } + + visibilities := getDumpVisibilities(t, db.db) + expected := map[int]bool{1: false, 2: true, 3: true, 4: false, 5: false, 6: true, 7: true} + if diff := cmp.Diff(expected, visibilities); diff != "" { + t.Errorf("unexpected visibility (-want +got):\n%s", diff) + } +} + +func TestUpdateDumpsVisibleFromTipMaxTraversalLimit(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + // This repository has the following commit graph (ancestors to the left): + // + // (MAX_TRAVERSAL_LIMIT + 1) -- ... -- 2 -- 1 -- 0 + + commits := map[string][]string{} + for i := 0; i < MaxTraversalLimit+1; i++ { + commits[makeCommit(i)] = []string{makeCommit(i + 1)} + } + + insertCommits(t, db.db, commits) + insertUploads(t, db.db, Upload{ID: 1, Commit: fmt.Sprintf("%040d", MaxTraversalLimit)}) + + if err := db.updateDumpsVisibleFromTip(context.Background(), nil, 50, makeCommit(MaxTraversalLimit)); err != nil { + t.Fatalf("unexpected error updating dumps visible from tip: %s", err) + } else { + visibilities := getDumpVisibilities(t, db.db) + expected := map[int]bool{1: true} + if diff := cmp.Diff(expected, visibilities); diff != "" { + t.Errorf("unexpected visibility (-want +got):\n%s", diff) + } + } + + if err := db.updateDumpsVisibleFromTip(context.Background(), nil, 50, makeCommit(1)); err != nil { + t.Fatalf("unexpected error updating dumps visible from tip: %s", err) + } else { + visibilities := getDumpVisibilities(t, db.db) + expected := map[int]bool{1: true} + if diff := cmp.Diff(expected, visibilities); diff != "" { + t.Errorf("unexpected visibility (-want +got):\n%s", diff) + } + } + + if err := db.updateDumpsVisibleFromTip(context.Background(), nil, 50, makeCommit(0)); err != nil { + t.Fatalf("unexpected error updating dumps visible from tip: %s", err) + } else { + visibilities := getDumpVisibilities(t, db.db) + expected := map[int]bool{1: false} + if diff := cmp.Diff(expected, visibilities); diff != "" { + t.Errorf("unexpected visibility (-want +got):\n%s", diff) + } + } +} diff --git a/cmd/precise-code-intel-api-server/internal/db/helpers_test.go b/cmd/precise-code-intel-api-server/internal/db/helpers_test.go new file mode 100644 index 00000000000..2aabafeea05 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/db/helpers_test.go @@ -0,0 +1,164 @@ +package db + +import ( + "context" + "database/sql" + "fmt" + "testing" + + "github.com/keegancsmith/sqlf" +) + +type PackageModel struct { + Scheme string + Name string + Version string + DumpID int +} + +type ReferenceModel struct { + Scheme string + Name string + Version string + DumpID int + Filter []byte +} + +// insertUploads populates the lsif_uploads table with the given upload models. +func insertUploads(t *testing.T, db *sql.DB, uploads ...Upload) { + for _, upload := range uploads { + if upload.Commit == "" { + upload.Commit = makeCommit(upload.ID) + } + if upload.State == "" { + upload.State = "completed" + } + if upload.RepositoryID == 0 { + upload.RepositoryID = 50 + } + if upload.Indexer == "" { + upload.Indexer = "lsif-go" + } + + query := sqlf.Sprintf(` + INSERT INTO lsif_uploads ( + id, + commit, + root, + visible_at_tip, + uploaded_at, + state, + failure_summary, + failure_stacktrace, + started_at, + finished_at, + tracing_context, + repository_id, + indexer + ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) + `, + upload.ID, + upload.Commit, + upload.Root, + upload.VisibleAtTip, + upload.UploadedAt, + upload.State, + upload.FailureSummary, + upload.FailureStacktrace, + upload.StartedAt, + upload.FinishedAt, + upload.TracingContext, + upload.RepositoryID, + upload.Indexer, + ) + + if _, err := db.ExecContext(context.Background(), query.Query(sqlf.PostgresBindVar), query.Args()...); err != nil { + t.Fatalf("unexpected error while inserting dump: %s", err) + } + } +} + +// insertPackages populates the lsif_packages table with the given package models. +func insertPackages(t *testing.T, db *sql.DB, packages ...PackageModel) { + for _, pkg := range packages { + query := sqlf.Sprintf(` + INSERT INTO lsif_packages ( + scheme, + name, + version, + dump_id + ) VALUES (%s, %s, %s, %s) + `, + pkg.Scheme, + pkg.Name, + pkg.Version, + pkg.DumpID, + ) + + if _, err := db.ExecContext(context.Background(), query.Query(sqlf.PostgresBindVar), query.Args()...); err != nil { + t.Fatalf("unexpected error while inserting package: %s", err) + } + } +} + +// insertReferences populates the lsif_references table with the given reference models. +func insertReferences(t *testing.T, db *sql.DB, references ...ReferenceModel) { + for _, reference := range references { + query := sqlf.Sprintf(` + INSERT INTO lsif_references ( + scheme, + name, + version, + dump_id, + filter + ) VALUES (%s, %s, %s, %s, %s) + `, + reference.Scheme, + reference.Name, + reference.Version, + reference.DumpID, + reference.Filter, + ) + + if _, err := db.ExecContext(context.Background(), query.Query(sqlf.PostgresBindVar), query.Args()...); err != nil { + t.Fatalf("unexpected error while inserting reference: %s", err) + } + } +} + +// insertCommits populates the lsif_commits table with the given commit-parent map. +func insertCommits(t *testing.T, db *sql.DB, commits map[string][]string) { + var values []*sqlf.Query + for k, vs := range commits { + if len(vs) == 0 { + values = append(values, sqlf.Sprintf("(%d, %s, %v)", 50, k, nil)) + } + + for _, v := range vs { + values = append(values, sqlf.Sprintf("(%d, %s, %s)", 50, k, v)) + } + } + + query := sqlf.Sprintf( + "INSERT INTO lsif_commits (repository_id, commit, parent_commit) VALUES %s", + sqlf.Join(values, ", "), + ) + + if _, err := db.ExecContext(context.Background(), query.Query(sqlf.PostgresBindVar), query.Args()...); err != nil { + t.Fatalf("unexpected error while inserting commits: %s", err) + } +} + +// getDumpVisibilities returns a map from dump identifiers to its visibility. Fails the test on error. +func getDumpVisibilities(t *testing.T, db *sql.DB) map[int]bool { + visibilities, err := scanVisibilities(db.Query("SELECT id, visible_at_tip FROM lsif_dumps")) + if err != nil { + t.Fatalf("unexpected error while scanning dump visibility: %s", err) + } + + return visibilities +} + +func makeCommit(i int) string { + return fmt.Sprintf("%040d", i) +} diff --git a/cmd/precise-code-intel-api-server/internal/db/packages.go b/cmd/precise-code-intel-api-server/internal/db/packages.go new file mode 100644 index 00000000000..0595087b749 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/db/packages.go @@ -0,0 +1,38 @@ +package db + +import ( + "context" + + "github.com/keegancsmith/sqlf" +) + +// GetPackage returns the dump that provides the package with the given scheme, name, and version and a flag indicating its existence. +func (db *dbImpl) GetPackage(ctx context.Context, scheme, name, version string) (Dump, bool, error) { + query := ` + SELECT + d.id, + d.commit, + d.root, + d.visible_at_tip, + d.uploaded_at, + d.state, + d.failure_summary, + d.failure_stacktrace, + d.started_at, + d.finished_at, + d.tracing_context, + d.repository_id, + d.indexer + FROM lsif_packages p + JOIN lsif_dumps d ON p.dump_id = d.id + WHERE p.scheme = %s AND p.name = %s AND p.version = %s + LIMIT 1 + ` + + dump, err := scanDump(db.queryRow(ctx, sqlf.Sprintf(query, scheme, name, version))) + if err != nil { + return Dump{}, false, ignoreErrNoRows(err) + } + + return dump, true, nil +} diff --git a/cmd/precise-code-intel-api-server/internal/db/packages_test.go b/cmd/precise-code-intel-api-server/internal/db/packages_test.go new file mode 100644 index 00000000000..c71cf181ed6 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/db/packages_test.go @@ -0,0 +1,76 @@ +package db + +import ( + "context" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/sourcegraph/sourcegraph/internal/db/dbconn" + "github.com/sourcegraph/sourcegraph/internal/db/dbtesting" +) + +func TestGetPackage(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + // Package does not exist initially + if _, exists, err := db.GetPackage(context.Background(), "gomod", "leftpad", "0.1.0"); err != nil { + t.Fatalf("unexpected error getting package: %s", err) + } else if exists { + t.Fatal("unexpected record") + } + + uploadedAt := time.Unix(1587396557, 0).UTC() + startedAt := uploadedAt.Add(time.Minute) + finishedAt := uploadedAt.Add(time.Minute * 2) + expected := Dump{ + ID: 1, + Commit: makeCommit(1), + Root: "sub/", + VisibleAtTip: true, + UploadedAt: uploadedAt, + State: "completed", + FailureSummary: nil, + FailureStacktrace: nil, + StartedAt: &startedAt, + FinishedAt: &finishedAt, + TracingContext: `{"id": 42}`, + RepositoryID: 50, + Indexer: "lsif-go", + } + + insertUploads(t, db.db, Upload{ + ID: expected.ID, + Commit: expected.Commit, + Root: expected.Root, + VisibleAtTip: expected.VisibleAtTip, + UploadedAt: expected.UploadedAt, + State: expected.State, + FailureSummary: expected.FailureSummary, + FailureStacktrace: expected.FailureStacktrace, + StartedAt: expected.StartedAt, + FinishedAt: expected.FinishedAt, + TracingContext: expected.TracingContext, + RepositoryID: expected.RepositoryID, + Indexer: expected.Indexer, + }) + + insertPackages(t, db.db, PackageModel{ + Scheme: "gomod", + Name: "leftpad", + Version: "0.1.0", + DumpID: 1, + }) + + if dump, exists, err := db.GetPackage(context.Background(), "gomod", "leftpad", "0.1.0"); err != nil { + t.Fatalf("unexpected error getting package: %s", err) + } else if !exists { + t.Fatal("expected record to exist") + } else if diff := cmp.Diff(expected, dump); diff != "" { + t.Errorf("unexpected dump (-want +got):\n%s", diff) + } +} diff --git a/cmd/precise-code-intel-api-server/internal/db/reference_pager.go b/cmd/precise-code-intel-api-server/internal/db/reference_pager.go new file mode 100644 index 00000000000..4acccd481b3 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/db/reference_pager.go @@ -0,0 +1,35 @@ +package db + +import "database/sql" + +// ReferencePager holds state for a reference result in a SQL transaction. Each page +// requested should have a consistent view into the database. +type ReferencePager interface { + TxCloser + + // PageFromOffset returns the page of references that starts at the given offset. + PageFromOffset(offset int) ([]Reference, error) +} + +type referencePager struct { + *txCloser + pageFromOffset func(offset int) ([]Reference, error) +} + +// PageFromOffset returns the page of references that starts at the given offset. +func (rp *referencePager) PageFromOffset(offset int) ([]Reference, error) { + return rp.pageFromOffset(offset) +} + +func newReferencePager(tx *sql.Tx, pageFromOffset func(offset int) ([]Reference, error)) ReferencePager { + return &referencePager{ + txCloser: &txCloser{tx}, + pageFromOffset: pageFromOffset, + } +} + +func newEmptyReferencePager(tx *sql.Tx) ReferencePager { + return newReferencePager(tx, func(offset int) ([]Reference, error) { + return nil, nil + }) +} diff --git a/cmd/precise-code-intel-api-server/internal/db/references.go b/cmd/precise-code-intel-api-server/internal/db/references.go new file mode 100644 index 00000000000..2f1f2a99aaa --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/db/references.go @@ -0,0 +1,111 @@ +package db + +import ( + "context" + + "github.com/keegancsmith/sqlf" +) + +// Reference is a subset of the lsif_references table which links a dump to a package from +// which it imports. The filter field encodes a bloom filter of the set of identifiers it +// imports from the package, which can be used to quickly filter out (on the server side) +// dumps that improt a package but not the target identifier. +type Reference struct { + DumpID int + Filter []byte +} + +// SameRepoPager returns a ReferencePager for dumps that belong to the given repository and commit and reference the package with the +// given scheme, name, and version. +func (db *dbImpl) SameRepoPager(ctx context.Context, repositoryID int, commit, scheme, name, version string, limit int) (_ int, _ ReferencePager, err error) { + tw, err := db.beginTx(ctx) + if err != nil { + return 0, nil, err + } + defer func() { + if err != nil { + err = closeTx(tw.tx, err) + } + }() + + visibleIDsQuery := `SELECT id FROM visible_ids` + visibleIDs, err := scanInts(tw.query(ctx, withBidirectionalLineage(visibleIDsQuery, repositoryID, commit))) + if err != nil { + return 0, nil, err + } + + if len(visibleIDs) == 0 { + return 0, newEmptyReferencePager(tw.tx), nil + } + + conds := []*sqlf.Query{ + sqlf.Sprintf("r.scheme = %s", scheme), + sqlf.Sprintf("r.name = %s", name), + sqlf.Sprintf("r.version = %s", version), + sqlf.Sprintf("r.dump_id IN (%s)", sqlf.Join(intsToQueries(visibleIDs), ", ")), + } + + countQuery := `SELECT COUNT(1) FROM lsif_references r WHERE %s` + totalCount, err := scanInt(tw.queryRow(ctx, sqlf.Sprintf(countQuery, sqlf.Join(conds, " AND ")))) + if err != nil { + return 0, nil, err + } + + pageFromOffset := func(offset int) ([]Reference, error) { + query := ` + SELECT d.id, r.filter FROM lsif_references r + LEFT JOIN lsif_dumps d on r.dump_id = d.id + WHERE %s ORDER BY d.root LIMIT %d OFFSET %d + ` + + return scanReferences(tw.query(ctx, sqlf.Sprintf(query, sqlf.Join(conds, " AND "), limit, offset))) + } + + return totalCount, newReferencePager(tw.tx, pageFromOffset), nil +} + +// PackageReferencePager returns a ReferencePager for dumps that belong to a remote repository (distinct from the given repository id) +// and reference the package with the given scheme, name, and version. All resulting dumps are visible at the tip of their repository's +// default branch. +func (db *dbImpl) PackageReferencePager(ctx context.Context, scheme, name, version string, repositoryID, limit int) (_ int, _ ReferencePager, err error) { + tw, err := db.beginTx(ctx) + if err != nil { + return 0, nil, err + } + defer func() { + if err != nil { + err = closeTx(tw.tx, err) + } + }() + + conds := []*sqlf.Query{ + sqlf.Sprintf("r.scheme = %s", scheme), + sqlf.Sprintf("r.name = %s", name), + sqlf.Sprintf("r.version = %s", version), + sqlf.Sprintf("d.repository_id != %s", repositoryID), + sqlf.Sprintf("d.visible_at_tip = true"), + } + + countQuery := ` + SELECT COUNT(1) FROM lsif_references r + LEFT JOIN lsif_dumps d ON r.dump_id = d.id + WHERE %s + ` + + totalCount, err := scanInt(tw.queryRow(ctx, sqlf.Sprintf(countQuery, sqlf.Join(conds, " AND ")))) + if err != nil { + return 0, nil, err + } + + pageFromOffset := func(offset int) ([]Reference, error) { + query := ` + SELECT d.id, r.filter FROM lsif_references r + LEFT JOIN lsif_dumps d ON r.dump_id = d.id + WHERE %s ORDER BY d.repository_id, d.root LIMIT %d OFFSET %d + ` + + return scanReferences(tw.query(ctx, sqlf.Sprintf(query, sqlf.Join(conds, " AND "), limit, offset))) + } + + return totalCount, newReferencePager(tw.tx, pageFromOffset), nil +} diff --git a/cmd/precise-code-intel-api-server/internal/db/references_test.go b/cmd/precise-code-intel-api-server/internal/db/references_test.go new file mode 100644 index 00000000000..91ccde1e50b --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/db/references_test.go @@ -0,0 +1,357 @@ +package db + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/sourcegraph/sourcegraph/internal/db/dbconn" + "github.com/sourcegraph/sourcegraph/internal/db/dbtesting" +) + +func TestSameRepoPager(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + insertUploads(t, db.db, + Upload{ID: 1, Commit: makeCommit(2), Root: "sub1/"}, + Upload{ID: 2, Commit: makeCommit(3), Root: "sub2/"}, + Upload{ID: 3, Commit: makeCommit(4), Root: "sub3/"}, + Upload{ID: 4, Commit: makeCommit(3), Root: "sub4/"}, + Upload{ID: 5, Commit: makeCommit(2), Root: "sub5/"}, + ) + + insertReferences(t, db.db, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 1, Filter: []byte("f1")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 2, Filter: []byte("f2")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 3, Filter: []byte("f3")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 4, Filter: []byte("f4")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 5, Filter: []byte("f5")}, + ) + + insertCommits(t, db.db, map[string][]string{ + makeCommit(1): {}, + makeCommit(2): {makeCommit(1)}, + makeCommit(3): {makeCommit(2)}, + makeCommit(4): {makeCommit(3)}, + }) + + totalCount, pager, err := db.SameRepoPager(context.Background(), 50, makeCommit(1), "gomod", "leftpad", "0.1.0", 5) + if err != nil { + t.Fatalf("unexpected error getting pager: %s", err) + } + defer func() { _ = pager.CloseTx(nil) }() + + if totalCount != 5 { + t.Errorf("unexpected dump. want=%d have=%d", 5, totalCount) + } + + expected := []Reference{ + {DumpID: 1, Filter: []byte("f1")}, + {DumpID: 2, Filter: []byte("f2")}, + {DumpID: 3, Filter: []byte("f3")}, + {DumpID: 4, Filter: []byte("f4")}, + {DumpID: 5, Filter: []byte("f5")}, + } + + if references, err := pager.PageFromOffset(0); err != nil { + t.Fatalf("unexpected error getting next page: %s", err) + } else if diff := cmp.Diff(expected, references); diff != "" { + t.Errorf("unexpected references (-want +got):\n%s", diff) + } +} + +func TestSameRepoPagerEmpty(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + totalCount, pager, err := db.SameRepoPager(context.Background(), 50, makeCommit(1), "gomod", "leftpad", "0.1.0", 5) + if err != nil { + t.Fatalf("unexpected error getting pager: %s", err) + } + defer func() { _ = pager.CloseTx(nil) }() + + if totalCount != 0 { + t.Errorf("unexpected dump. want=%d have=%d", 0, totalCount) + } +} + +func TestSameRepoPagerMultiplePages(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + insertUploads(t, db.db, + Upload{ID: 1, Commit: makeCommit(1), Root: "sub1/"}, + Upload{ID: 2, Commit: makeCommit(1), Root: "sub2/"}, + Upload{ID: 3, Commit: makeCommit(1), Root: "sub3/"}, + Upload{ID: 4, Commit: makeCommit(1), Root: "sub4/"}, + Upload{ID: 5, Commit: makeCommit(1), Root: "sub5/"}, + Upload{ID: 6, Commit: makeCommit(1), Root: "sub6/"}, + Upload{ID: 7, Commit: makeCommit(1), Root: "sub7/"}, + Upload{ID: 8, Commit: makeCommit(1), Root: "sub8/"}, + Upload{ID: 9, Commit: makeCommit(1), Root: "sub9/"}, + ) + + insertReferences(t, db.db, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 1, Filter: []byte("f1")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 2, Filter: []byte("f2")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 3, Filter: []byte("f3")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 4, Filter: []byte("f4")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 5, Filter: []byte("f5")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 6, Filter: []byte("f6")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 7, Filter: []byte("f7")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 8, Filter: []byte("f8")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 9, Filter: []byte("f9")}, + ) + + insertCommits(t, db.db, map[string][]string{ + makeCommit(1): {}, + }) + + totalCount, pager, err := db.SameRepoPager(context.Background(), 50, makeCommit(1), "gomod", "leftpad", "0.1.0", 3) + if err != nil { + t.Fatalf("unexpected error getting pager: %s", err) + } + defer func() { _ = pager.CloseTx(nil) }() + + if totalCount != 9 { + t.Errorf("unexpected dump. want=%d have=%d", 9, totalCount) + } + + expected := []Reference{ + {DumpID: 1, Filter: []byte("f1")}, + {DumpID: 2, Filter: []byte("f2")}, + {DumpID: 3, Filter: []byte("f3")}, + {DumpID: 4, Filter: []byte("f4")}, + {DumpID: 5, Filter: []byte("f5")}, + {DumpID: 6, Filter: []byte("f6")}, + {DumpID: 7, Filter: []byte("f7")}, + {DumpID: 8, Filter: []byte("f8")}, + {DumpID: 9, Filter: []byte("f9")}, + } + + for lo := 0; lo < len(expected); lo++ { + hi := lo + 3 + if hi > len(expected) { + hi = len(expected) + } + + if references, err := pager.PageFromOffset(lo); err != nil { + t.Fatalf("unexpected error getting page at offset %d: %s", lo, err) + } else if diff := cmp.Diff(expected[lo:hi], references); diff != "" { + t.Errorf("unexpected references at offset %d (-want +got):\n%s", lo, diff) + } + } +} + +func TestSameRepoPagerVisibility(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + insertUploads(t, db.db, + Upload{ID: 1, Commit: makeCommit(1), Root: "sub1/"}, // not visible + Upload{ID: 2, Commit: makeCommit(2), Root: "sub2/"}, // not visible + Upload{ID: 3, Commit: makeCommit(3), Root: "sub1/"}, + Upload{ID: 4, Commit: makeCommit(4), Root: "sub2/"}, + Upload{ID: 5, Commit: makeCommit(5), Root: "sub5/"}, + ) + + insertReferences(t, db.db, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 1, Filter: []byte("f1")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 2, Filter: []byte("f2")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 3, Filter: []byte("f3")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 4, Filter: []byte("f4")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 5, Filter: []byte("f5")}, + ) + + insertCommits(t, db.db, map[string][]string{ + makeCommit(1): {}, + makeCommit(2): {makeCommit(1)}, + makeCommit(3): {makeCommit(2)}, + makeCommit(4): {makeCommit(3)}, + makeCommit(5): {makeCommit(4)}, + makeCommit(6): {makeCommit(5)}, + }) + + totalCount, pager, err := db.SameRepoPager(context.Background(), 50, makeCommit(6), "gomod", "leftpad", "0.1.0", 5) + if err != nil { + t.Fatalf("unexpected error getting pager: %s", err) + } + defer func() { _ = pager.CloseTx(nil) }() + + if totalCount != 3 { + t.Errorf("unexpected dump. want=%d have=%d", 5, totalCount) + } + + expected := []Reference{ + {DumpID: 3, Filter: []byte("f3")}, + {DumpID: 4, Filter: []byte("f4")}, + {DumpID: 5, Filter: []byte("f5")}, + } + + if references, err := pager.PageFromOffset(0); err != nil { + t.Fatalf("unexpected error getting next page: %s", err) + } else if diff := cmp.Diff(expected, references); diff != "" { + t.Errorf("unexpected references (-want +got):\n%s", diff) + } +} + +func TestPackageReferencePager(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + insertUploads(t, db.db, + Upload{ID: 1, Commit: makeCommit(1), VisibleAtTip: true}, + Upload{ID: 2, Commit: makeCommit(2), VisibleAtTip: true, RepositoryID: 51}, + Upload{ID: 3, Commit: makeCommit(3), VisibleAtTip: true, RepositoryID: 52}, + Upload{ID: 4, Commit: makeCommit(4), VisibleAtTip: true, RepositoryID: 53}, + Upload{ID: 5, Commit: makeCommit(5), VisibleAtTip: true, RepositoryID: 54}, + Upload{ID: 6, Commit: makeCommit(6), VisibleAtTip: false, RepositoryID: 55}, + Upload{ID: 7, Commit: makeCommit(6), VisibleAtTip: true, RepositoryID: 56}, + ) + + insertReferences(t, db.db, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 1, Filter: []byte("f1")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 2, Filter: []byte("f2")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 3, Filter: []byte("f3")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 4, Filter: []byte("f4")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 5, Filter: []byte("f5")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 6, Filter: []byte("f6")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 7, Filter: []byte("f7")}, + ) + + totalCount, pager, err := db.PackageReferencePager(context.Background(), "gomod", "leftpad", "0.1.0", 50, 5) + if err != nil { + t.Fatalf("unexpected error getting pager: %s", err) + } + defer func() { _ = pager.CloseTx(nil) }() + + if totalCount != 5 { + t.Errorf("unexpected dump. want=%d have=%d", 5, totalCount) + } + + expected := []Reference{ + {DumpID: 2, Filter: []byte("f2")}, + {DumpID: 3, Filter: []byte("f3")}, + {DumpID: 4, Filter: []byte("f4")}, + {DumpID: 5, Filter: []byte("f5")}, + {DumpID: 7, Filter: []byte("f7")}, + } + + if references, err := pager.PageFromOffset(0); err != nil { + t.Fatalf("unexpected error getting next page: %s", err) + } else if diff := cmp.Diff(expected, references); diff != "" { + t.Errorf("unexpected references (-want +got):\n%s", diff) + } +} + +func TestPackageReferencePagerEmpty(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + totalCount, pager, err := db.PackageReferencePager(context.Background(), "gomod", "leftpad", "0.1.0", 50, 5) + if err != nil { + t.Fatalf("unexpected error getting pager: %s", err) + } + defer func() { _ = pager.CloseTx(nil) }() + + if totalCount != 0 { + t.Errorf("unexpected dump. want=%d have=%d", 0, totalCount) + } +} + +func TestPackageReferencePagerPages(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + insertUploads(t, db.db, + Upload{ID: 1, Commit: makeCommit(1), VisibleAtTip: true, RepositoryID: 51}, + Upload{ID: 2, Commit: makeCommit(2), VisibleAtTip: true, RepositoryID: 52}, + Upload{ID: 3, Commit: makeCommit(3), VisibleAtTip: true, RepositoryID: 53}, + Upload{ID: 4, Commit: makeCommit(4), VisibleAtTip: true, RepositoryID: 54}, + Upload{ID: 5, Commit: makeCommit(5), VisibleAtTip: true, RepositoryID: 55}, + Upload{ID: 6, Commit: makeCommit(6), VisibleAtTip: true, RepositoryID: 56}, + Upload{ID: 7, Commit: makeCommit(7), VisibleAtTip: true, RepositoryID: 57}, + Upload{ID: 8, Commit: makeCommit(8), VisibleAtTip: true, RepositoryID: 58}, + Upload{ID: 9, Commit: makeCommit(9), VisibleAtTip: true, RepositoryID: 59}, + ) + + insertReferences(t, db.db, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 1, Filter: []byte("f1")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 2, Filter: []byte("f2")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 3, Filter: []byte("f3")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 4, Filter: []byte("f4")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 5, Filter: []byte("f5")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 6, Filter: []byte("f6")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 7, Filter: []byte("f7")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 8, Filter: []byte("f8")}, + ReferenceModel{Scheme: "gomod", Name: "leftpad", Version: "0.1.0", DumpID: 9, Filter: []byte("f9")}, + ) + + totalCount, pager, err := db.PackageReferencePager(context.Background(), "gomod", "leftpad", "0.1.0", 50, 3) + if err != nil { + t.Fatalf("unexpected error getting pager: %s", err) + } + defer func() { _ = pager.CloseTx(nil) }() + + if totalCount != 9 { + t.Errorf("unexpected dump. want=%d have=%d", 9, totalCount) + } + + testCases := []struct { + offset int + lo int + hi int + }{ + {0, 0, 3}, + {1, 1, 4}, + {2, 2, 5}, + {3, 3, 6}, + {4, 4, 7}, + {5, 5, 8}, + {6, 6, 9}, + {7, 7, 9}, + {8, 8, 9}, + } + + expected := []Reference{ + {DumpID: 1, Filter: []byte("f1")}, + {DumpID: 2, Filter: []byte("f2")}, + {DumpID: 3, Filter: []byte("f3")}, + {DumpID: 4, Filter: []byte("f4")}, + {DumpID: 5, Filter: []byte("f5")}, + {DumpID: 6, Filter: []byte("f6")}, + {DumpID: 7, Filter: []byte("f7")}, + {DumpID: 8, Filter: []byte("f8")}, + {DumpID: 9, Filter: []byte("f9")}, + } + + for _, testCase := range testCases { + if references, err := pager.PageFromOffset(testCase.offset); err != nil { + t.Fatalf("unexpected error getting page at offset %d: %s", testCase.offset, err) + } else if diff := cmp.Diff(expected[testCase.lo:testCase.hi], references); diff != "" { + t.Errorf("unexpected references at offset %d (-want +got):\n%s", testCase.offset, diff) + } + } +} diff --git a/cmd/precise-code-intel-api-server/internal/db/scan.go b/cmd/precise-code-intel-api-server/internal/db/scan.go new file mode 100644 index 00000000000..eb2ecdd03e4 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/db/scan.go @@ -0,0 +1,203 @@ +package db + +import ( + "database/sql" +) + +// Scanner is the common interface shared by *sql.Row and *sql.Rows. +type Scanner interface { + // Scan copies the values of the current row into the values pointed at by dest. + Scan(dest ...interface{}) error +} + +// scanDump populates a Dump value from the given scanner. +func scanDump(scanner Scanner) (dump Dump, err error) { + err = scanner.Scan( + &dump.ID, + &dump.Commit, + &dump.Root, + &dump.VisibleAtTip, + &dump.UploadedAt, + &dump.State, + &dump.FailureSummary, + &dump.FailureStacktrace, + &dump.StartedAt, + &dump.FinishedAt, + &dump.TracingContext, + &dump.RepositoryID, + &dump.Indexer, + ) + return dump, err +} + +// scanDumps reads the given set of dump rows and returns a slice of resulting values. +// This method should be called directly with the return value of `*db.queryRows`. +func scanDumps(rows *sql.Rows, err error) ([]Dump, error) { + if err != nil { + return nil, err + } + defer rows.Close() + + var dumps []Dump + for rows.Next() { + dump, err := scanDump(rows) + if err != nil { + return nil, err + } + + dumps = append(dumps, dump) + } + + return dumps, nil +} + +// scanUpload populates an Upload value from the given scanner. +func scanUpload(scanner Scanner) (upload Upload, err error) { + err = scanner.Scan( + &upload.ID, + &upload.Commit, + &upload.Root, + &upload.VisibleAtTip, + &upload.UploadedAt, + &upload.State, + &upload.FailureSummary, + &upload.FailureStacktrace, + &upload.StartedAt, + &upload.FinishedAt, + &upload.TracingContext, + &upload.RepositoryID, + &upload.Indexer, + &upload.Rank, + ) + return upload, err +} + +// scanUploads reads the given set of upload rows and returns a slice of resulting +// values. This method should be called directly with the return value of `*db.queryRows`. +func scanUploads(rows *sql.Rows, err error) ([]Upload, error) { + if err != nil { + return nil, err + } + defer rows.Close() + + var uploads []Upload + for rows.Next() { + upload, err := scanUpload(rows) + if err != nil { + return nil, err + } + + uploads = append(uploads, upload) + } + + return uploads, nil +} + +// scanReference populates a Reference value from the given scanner. +func scanReference(scanner Scanner) (reference Reference, err error) { + err = scanner.Scan(&reference.DumpID, &reference.Filter) + return reference, err +} + +// scanReferences reads the given set of reference rows and returns a slice of resulting +// values. This method should be called directly with the return value of `*db.queryRows`. +func scanReferences(rows *sql.Rows, err error) ([]Reference, error) { + if err != nil { + return nil, err + } + defer rows.Close() + + var references []Reference + for rows.Next() { + reference, err := scanReference(rows) + if err != nil { + return nil, err + } + + references = append(references, reference) + } + + return references, nil +} + +// scanInt populates an integer value from the given scanner. +func scanInt(scanner Scanner) (value int, err error) { + err = scanner.Scan(&value) + return value, err +} + +// scanInts reads the given set of `(int)` rows and returns a slice of resulting values. +// This method should be called directly with the return value of `*db.queryRows`. +func scanInts(rows *sql.Rows, err error) ([]int, error) { + if err != nil { + return nil, err + } + defer rows.Close() + + var values []int + for rows.Next() { + value, err := scanInt(rows) + if err != nil { + return nil, err + } + + values = append(values, value) + } + + return values, nil +} + +// scanState populates an integer and string from the given scanner. +func scanState(scanner Scanner) (repositoryID int, state string, err error) { + err = scanner.Scan(&repositoryID, &state) + return repositoryID, state, err +} + +// scanStates reads the given set of `(id, state)` rows and returns a map from id to its +// state. This method should be called directly with the return value of `*db.queryRows`. +func scanStates(rows *sql.Rows, err error) (map[int]string, error) { + if err != nil { + return nil, err + } + defer rows.Close() + + states := map[int]string{} + for rows.Next() { + repositoryID, state, err := scanState(rows) + if err != nil { + return nil, err + } + + states[repositoryID] = state + } + + return states, nil +} + +// scanVisibility populates an integer and boolean from the given scanner. +func scanVisibility(scanner Scanner) (repositoryID int, visibleAtTip bool, err error) { + err = scanner.Scan(&repositoryID, &visibleAtTip) + return repositoryID, visibleAtTip, err +} + +// scanVisibilities reads the given set of `(id, visible_at_tip)` rows and returns a map +// from id to its visibility. This method should be called directly with the return value +// of `*db.queryRows`. +func scanVisibilities(rows *sql.Rows, err error) (map[int]bool, error) { + if err != nil { + return nil, err + } + defer rows.Close() + + visibilities := map[int]bool{} + for rows.Next() { + repositoryID, visibleAtTip, err := scanVisibility(rows) + if err != nil { + return nil, err + } + + visibilities[repositoryID] = visibleAtTip + } + + return visibilities, nil +} diff --git a/cmd/precise-code-intel-api-server/internal/db/tx.go b/cmd/precise-code-intel-api-server/internal/db/tx.go new file mode 100644 index 00000000000..0cf20538230 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/db/tx.go @@ -0,0 +1,55 @@ +package db + +import ( + "context" + "database/sql" + + "github.com/hashicorp/go-multierror" + "github.com/keegancsmith/sqlf" +) + +// TxCloser is a convenience wrapper for closing SQL transactions. +type TxCloser interface { + // CloseTx commits the transaction on a nil error value and performs a rollback + // otherwise. If an error occurs during commit or rollback of the transaction, + // the error is added to the resulting error value. + CloseTx(err error) error +} + +type txCloser struct { + tx *sql.Tx +} + +func (txc *txCloser) CloseTx(err error) error { + return closeTx(txc.tx, err) +} + +func closeTx(tx *sql.Tx, err error) error { + if err != nil { + if rollErr := tx.Rollback(); rollErr != nil { + err = multierror.Append(err, rollErr) + } + return err + } + + return tx.Commit() +} + +type transactionWrapper struct { + tx *sql.Tx +} + +// query performs QueryContext on the underlying transaction. +func (tw *transactionWrapper) query(ctx context.Context, query *sqlf.Query) (*sql.Rows, error) { + return tw.tx.QueryContext(ctx, query.Query(sqlf.PostgresBindVar), query.Args()...) +} + +// queryRow performs QueryRow on the underlying transaction. +func (tw *transactionWrapper) queryRow(ctx context.Context, query *sqlf.Query) *sql.Row { + return tw.tx.QueryRowContext(ctx, query.Query(sqlf.PostgresBindVar), query.Args()...) +} + +// exec performs Exec on the underlying transaction. +func (tw *transactionWrapper) exec(ctx context.Context, query *sqlf.Query) (sql.Result, error) { + return tw.tx.ExecContext(ctx, query.Query(sqlf.PostgresBindVar), query.Args()...) +} diff --git a/cmd/precise-code-intel-api-server/internal/db/uploads.go b/cmd/precise-code-intel-api-server/internal/db/uploads.go new file mode 100644 index 00000000000..e5c78f5550e --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/db/uploads.go @@ -0,0 +1,240 @@ +package db + +import ( + "context" + "time" + + "github.com/keegancsmith/sqlf" +) + +// StalledUploadMaxAge is the maximum allowable duration between updating the state of an +// upload as "processing" and locking the upload row during processing. An unlocked row that +// is marked as processing likely indicates that the worker that dequeued the upload has died. +// There should be a nearly-zero delay between these states during normal operation. +const StalledUploadMaxAge = time.Second * 5 + +// Upload is a subset of the lsif_uploads table and stores both processed and unprocessed +// records. +type Upload struct { + ID int `json:"id"` + Commit string `json:"commit"` + Root string `json:"root"` + VisibleAtTip bool `json:"visibleAtTip"` + UploadedAt time.Time `json:"uploadedAt"` + State string `json:"state"` + FailureSummary *string `json:"failureSummary"` + FailureStacktrace *string `json:"failureStacktrace"` + StartedAt *time.Time `json:"startedAt"` + FinishedAt *time.Time `json:"finishedAt"` + TracingContext string `json:"tracingContext"` + RepositoryID int `json:"repositoryId"` + Indexer string `json:"indexer"` + Rank *int `json:"placeInQueue"` +} + +// GetUploadByID returns an upload by its identifier and boolean flag indicating its existence. +func (db *dbImpl) GetUploadByID(ctx context.Context, id int) (Upload, bool, error) { + query := ` + SELECT + u.id, + u.commit, + u.root, + u.visible_at_tip, + u.uploaded_at, + u.state, + u.failure_summary, + u.failure_stacktrace, + u.started_at, + u.finished_at, + u.tracing_context, + u.repository_id, + u.indexer, + s.rank + FROM lsif_uploads u + LEFT JOIN ( + SELECT r.id, RANK() OVER (ORDER BY r.uploaded_at) as rank + FROM lsif_uploads r + WHERE r.state = 'queued' + ) s + ON u.id = s.id + WHERE u.id = %s + ` + + upload, err := scanUpload(db.queryRow(ctx, sqlf.Sprintf(query, id))) + if err != nil { + return Upload{}, false, ignoreErrNoRows(err) + } + + return upload, true, nil +} + +// GetUploadsByRepo returns a list of uploads for a particular repo and the total count of records matching the given conditions. +func (db *dbImpl) GetUploadsByRepo(ctx context.Context, repositoryID int, state, term string, visibleAtTip bool, limit, offset int) (_ []Upload, _ int, err error) { + tw, err := db.beginTx(ctx) + if err != nil { + return nil, 0, err + } + defer func() { + err = closeTx(tw.tx, err) + }() + + var conds []*sqlf.Query + conds = append(conds, sqlf.Sprintf("u.repository_id = %s", repositoryID)) + if state != "" { + conds = append(conds, sqlf.Sprintf("u.state = %s", state)) + } + if term != "" { + conds = append(conds, makeSearchCondition(term)) + } + if visibleAtTip { + conds = append(conds, sqlf.Sprintf("u.visible_at_tip = true")) + } + + countQuery := `SELECT COUNT(1) FROM lsif_uploads u WHERE %s` + count, err := scanInt(tw.queryRow(ctx, sqlf.Sprintf(countQuery, sqlf.Join(conds, " AND ")))) + if err != nil { + return nil, 0, err + } + + query := ` + SELECT + u.id, + u.commit, + u.root, + u.visible_at_tip, + u.uploaded_at, + u.state, + u.failure_summary, + u.failure_stacktrace, + u.started_at, + u.finished_at, + u.tracing_context, + u.repository_id, + u.indexer, + s.rank + FROM lsif_uploads u + LEFT JOIN ( + SELECT r.id, RANK() OVER (ORDER BY r.uploaded_at) as rank + FROM lsif_uploads r + WHERE r.state = 'queued' + ) s + ON u.id = s.id + WHERE %s ORDER BY uploaded_at DESC LIMIT %d OFFSET %d + ` + + uploads, err := scanUploads(tw.query(ctx, sqlf.Sprintf(query, sqlf.Join(conds, " AND "), limit, offset))) + if err != nil { + return nil, 0, err + } + + return uploads, count, nil +} + +// makeSearchCondition returns a disjunction of LIKE clauses against all searchable columns of an upload. +func makeSearchCondition(term string) *sqlf.Query { + searchableColumns := []string{ + "commit", + "root", + "indexer", + "failure_summary", + "failure_stacktrace", + } + + var termConds []*sqlf.Query + for _, column := range searchableColumns { + termConds = append(termConds, sqlf.Sprintf("u."+column+" LIKE %s", "%"+term+"%")) + } + + return sqlf.Sprintf("(%s)", sqlf.Join(termConds, " OR ")) +} + +// Enqueue inserts a new upload with a "queued" state, returning its identifier and a TxCloser that must be closed to commit the transaction. +func (db *dbImpl) Enqueue(ctx context.Context, commit, root, tracingContext string, repositoryID int, indexerName string) (_ int, _ TxCloser, err error) { + tw, err := db.beginTx(ctx) + if err != nil { + return 0, nil, err + } + defer func() { + if err != nil { + err = closeTx(tw.tx, err) + } + }() + + query := ` + INSERT INTO lsif_uploads (commit, root, tracing_context, repository_id, indexer) + VALUES (%s, %s, %s, %s, %s) + RETURNING id + ` + + id, err := scanInt(tw.queryRow(ctx, sqlf.Sprintf(query, commit, root, tracingContext, repositoryID, indexerName))) + if err != nil { + return 0, nil, err + } + + return id, &txCloser{tw.tx}, nil +} + +// GetStates returns the states for the uploads with the given identifiers. +func (db *dbImpl) GetStates(ctx context.Context, ids []int) (map[int]string, error) { + query := `SELECT id, state FROM lsif_uploads WHERE id IN (%s)` + return scanStates(db.query(ctx, sqlf.Sprintf(query, sqlf.Join(intsToQueries(ids), ", ")))) +} + +// DeleteUploadByID deletes an upload by its identifier. If the upload was visible at the tip of its repository's default branch, +// the visibility of all uploads for that repository are recalculated. The given function is expected to return the newest commit +// on the default branch when invoked. +func (db *dbImpl) DeleteUploadByID(ctx context.Context, id int, getTipCommit func(repositoryID int) (string, error)) (_ bool, err error) { + tw, err := db.beginTx(ctx) + if err != nil { + return false, err + } + defer func() { + err = closeTx(tw.tx, err) + }() + + query := ` + DELETE FROM lsif_uploads + WHERE id = %s + RETURNING repository_id, visible_at_tip + ` + + repositoryID, visibleAtTip, err := scanVisibility(tw.queryRow(ctx, sqlf.Sprintf(query, id))) + if err != nil { + return false, ignoreErrNoRows(err) + } + + if !visibleAtTip { + return true, nil + } + + tipCommit, err := getTipCommit(repositoryID) + if err != nil { + return false, err + } + + if err := db.updateDumpsVisibleFromTip(ctx, tw, repositoryID, tipCommit); err != nil { + return false, err + } + + return true, nil +} + +// ResetStalled moves all unlocked uploads processing for more than `StalledUploadMaxAge` back to the queued state. +// This method returns a list of updated upload identifiers. +func (db *dbImpl) ResetStalled(ctx context.Context, now time.Time) ([]int, error) { + query := ` + UPDATE lsif_uploads u SET state = 'queued', started_at = null WHERE id = ANY( + SELECT id FROM lsif_uploads + WHERE state = 'processing' AND %s - started_at > (%s * interval '1 second') + FOR UPDATE SKIP LOCKED + ) + RETURNING u.id + ` + + ids, err := scanInts(db.query(ctx, sqlf.Sprintf(query, now.UTC(), StalledUploadMaxAge/time.Second))) + if err != nil { + return nil, err + } + + return ids, nil +} diff --git a/cmd/precise-code-intel-api-server/internal/db/uploads_test.go b/cmd/precise-code-intel-api-server/internal/db/uploads_test.go new file mode 100644 index 00000000000..5fb5793dd1b --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/db/uploads_test.go @@ -0,0 +1,426 @@ +package db + +import ( + "context" + "errors" + "fmt" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/sourcegraph/sourcegraph/internal/db/dbconn" + "github.com/sourcegraph/sourcegraph/internal/db/dbtesting" +) + +type printableRank struct{ value *int } + +func (r printableRank) String() string { + if r.value == nil { + return "nil" + } + return fmt.Sprintf("%d", r.value) +} + +func TestGetUploadByID(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + // Upload does not exist initially + if _, exists, err := db.GetUploadByID(context.Background(), 1); err != nil { + t.Fatalf("unexpected error getting upload: %s", err) + } else if exists { + t.Fatal("unexpected record") + } + + uploadedAt := time.Unix(1587396557, 0).UTC() + startedAt := uploadedAt.Add(time.Minute) + expected := Upload{ + ID: 1, + Commit: makeCommit(1), + Root: "sub/", + VisibleAtTip: true, + UploadedAt: uploadedAt, + State: "processing", + FailureSummary: nil, + FailureStacktrace: nil, + StartedAt: &startedAt, + FinishedAt: nil, + TracingContext: `{"id": 42}`, + RepositoryID: 123, + Indexer: "lsif-go", + Rank: nil, + } + + insertUploads(t, db.db, expected) + + if upload, exists, err := db.GetUploadByID(context.Background(), 1); err != nil { + t.Fatalf("unexpected error getting upload: %s", err) + } else if !exists { + t.Fatal("expected record to exist") + } else if diff := cmp.Diff(expected, upload); diff != "" { + t.Errorf("unexpected upload (-want +got):\n%s", diff) + } +} + +func TestGetQueuedUploadRank(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + t1 := time.Unix(1587396557, 0).UTC() + t2 := t1.Add(+time.Minute * 5) + t3 := t1.Add(+time.Minute * 3) + t4 := t1.Add(+time.Minute * 1) + t5 := t1.Add(+time.Minute * 4) + t6 := t1.Add(+time.Minute * 2) + + insertUploads(t, db.db, + Upload{ID: 1, UploadedAt: t1, State: "queued"}, + Upload{ID: 2, UploadedAt: t2, State: "queued"}, + Upload{ID: 3, UploadedAt: t3, State: "queued"}, + Upload{ID: 4, UploadedAt: t4, State: "queued"}, + Upload{ID: 5, UploadedAt: t5, State: "queued"}, + Upload{ID: 6, UploadedAt: t6, State: "processing"}, + ) + + if upload, _, _ := db.GetUploadByID(context.Background(), 1); upload.Rank == nil || *upload.Rank != 1 { + t.Errorf("unexpected rank. want=%d have=%s", 1, printableRank{upload.Rank}) + } + if upload, _, _ := db.GetUploadByID(context.Background(), 2); upload.Rank == nil || *upload.Rank != 5 { + t.Errorf("unexpected rank. want=%d have=%s", 5, printableRank{upload.Rank}) + } + if upload, _, _ := db.GetUploadByID(context.Background(), 3); upload.Rank == nil || *upload.Rank != 3 { + t.Errorf("unexpected rank. want=%d have=%s", 3, printableRank{upload.Rank}) + } + if upload, _, _ := db.GetUploadByID(context.Background(), 4); upload.Rank == nil || *upload.Rank != 2 { + t.Errorf("unexpected rank. want=%d have=%s", 2, printableRank{upload.Rank}) + } + if upload, _, _ := db.GetUploadByID(context.Background(), 5); upload.Rank == nil || *upload.Rank != 4 { + t.Errorf("unexpected rank. want=%d have=%s", 4, printableRank{upload.Rank}) + } + + // Only considers queued uploads to determine rank + if upload, _, _ := db.GetUploadByID(context.Background(), 6); upload.Rank != nil { + t.Errorf("unexpected rank. want=%s have=%s", "nil", printableRank{upload.Rank}) + } +} + +func TestGetUploadsByRepo(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + t1 := time.Unix(1587396557, 0).UTC() + t2 := t1.Add(-time.Minute * 1) + t3 := t1.Add(-time.Minute * 2) + t4 := t1.Add(-time.Minute * 3) + t5 := t1.Add(-time.Minute * 4) + t6 := t1.Add(-time.Minute * 5) + t7 := t1.Add(-time.Minute * 6) + t8 := t1.Add(-time.Minute * 7) + t9 := t1.Add(-time.Minute * 8) + t10 := t1.Add(-time.Minute * 9) + failureSummary := "unlucky 333" + + insertUploads(t, db.db, + Upload{ID: 1, Commit: makeCommit(3331), UploadedAt: t1, Root: "sub1/", State: "queued"}, + Upload{ID: 2, UploadedAt: t2, VisibleAtTip: true, State: "errored", FailureSummary: &failureSummary, Indexer: "lsif-tsc"}, + Upload{ID: 3, Commit: makeCommit(3333), UploadedAt: t3, Root: "sub2/", State: "queued"}, + Upload{ID: 4, UploadedAt: t4, State: "queued", RepositoryID: 51}, + Upload{ID: 5, Commit: makeCommit(3333), UploadedAt: t5, Root: "sub1/", VisibleAtTip: true, State: "processing", Indexer: "lsif-tsc"}, + Upload{ID: 6, UploadedAt: t6, Root: "sub2/", State: "processing"}, + Upload{ID: 7, UploadedAt: t7, Root: "sub1/", VisibleAtTip: true, Indexer: "lsif-tsc"}, + Upload{ID: 8, UploadedAt: t8, VisibleAtTip: true, Indexer: "lsif-tsc"}, + Upload{ID: 9, UploadedAt: t9, State: "queued"}, + Upload{ID: 10, UploadedAt: t10, Root: "sub1/", Indexer: "lsif-tsc"}, + ) + + testCases := []struct { + state string + term string + visibleAtTip bool + expectedIDs []int + }{ + {expectedIDs: []int{1, 2, 3, 5, 6, 7, 8, 9, 10}}, + {state: "completed", expectedIDs: []int{7, 8, 10}}, + {term: "sub", expectedIDs: []int{1, 3, 5, 6, 7, 10}}, // searches root + {term: "003", expectedIDs: []int{1, 3, 5}}, // searches commits + {term: "333", expectedIDs: []int{1, 2, 3, 5}}, // searches commits and failure summary + {term: "tsc", expectedIDs: []int{2, 5, 7, 8, 10}}, // searches indexer + {visibleAtTip: true, expectedIDs: []int{2, 5, 7, 8}}, + } + + for _, testCase := range testCases { + name := fmt.Sprintf("state=%s term=%s visibleAtTip=%v", testCase.state, testCase.term, testCase.visibleAtTip) + + t.Run(name, func(t *testing.T) { + for lo := 0; lo < len(testCase.expectedIDs); lo++ { + hi := lo + 3 + if hi > len(testCase.expectedIDs) { + hi = len(testCase.expectedIDs) + } + + uploads, totalCount, err := db.GetUploadsByRepo(context.Background(), 50, testCase.state, testCase.term, testCase.visibleAtTip, 3, lo) + if err != nil { + t.Fatalf("unexpected error getting uploads for repo: %s", err) + } + if totalCount != len(testCase.expectedIDs) { + t.Errorf("unexpected total count. want=%d have=%d", len(testCase.expectedIDs), totalCount) + } + + var ids []int + for _, upload := range uploads { + ids = append(ids, upload.ID) + } + + if diff := cmp.Diff(testCase.expectedIDs[lo:hi], ids); diff != "" { + t.Errorf("unexpected upload ids at offset %d (-want +got):\n%s", lo, diff) + } + } + }) + } +} + +func TestEnqueue(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + id, closer, err := db.Enqueue(context.Background(), makeCommit(1), "sub/", `{"id": 42}`, 50, "lsif-go") + if err != nil { + t.Fatalf("unexpected error enqueueing upload: %s", err) + } + + // Upload does not exist before transaction commit + if _, exists, err := db.GetUploadByID(context.Background(), id); err != nil { + t.Fatalf("unexpected error getting upload: %s", err) + } else if exists { + t.Fatal("unexpected record") + } + + // Commit transaction + _ = closer.CloseTx(nil) + + rank := 1 + expected := Upload{ + ID: id, + Commit: makeCommit(1), + Root: "sub/", + VisibleAtTip: false, + UploadedAt: time.Time{}, + State: "queued", + FailureSummary: nil, + FailureStacktrace: nil, + StartedAt: nil, + FinishedAt: nil, + TracingContext: `{"id": 42}`, + RepositoryID: 50, + Indexer: "lsif-go", + Rank: &rank, + } + + if upload, exists, err := db.GetUploadByID(context.Background(), id); err != nil { + t.Fatalf("unexpected error getting upload: %s", err) + } else if !exists { + t.Fatal("expected record to exist") + } else { + // Update auto-generated timestamp + expected.UploadedAt = upload.UploadedAt + + if diff := cmp.Diff(expected, upload); diff != "" { + t.Errorf("unexpected upload (-want +got):\n%s", diff) + } + } +} + +func TestEnqueueRollback(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + id, closer, err := db.Enqueue(context.Background(), makeCommit(1), "sub/", `{"id": 42}`, 50, "lsif-go") + if err != nil { + t.Fatalf("unexpected error enqueueing upload: %s", err) + } + _ = closer.CloseTx(errors.New("")) + + // Upload does not exist after rollback + if _, exists, err := db.GetUploadByID(context.Background(), id); err != nil { + t.Fatalf("unexpected error getting upload: %s", err) + } else if exists { + t.Fatal("unexpected record") + } +} + +func TestGetStates(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + insertUploads(t, db.db, + Upload{ID: 1, State: "queued"}, + Upload{ID: 2}, + Upload{ID: 3, State: "processing"}, + Upload{ID: 4, State: "errored"}, + ) + + expected := map[int]string{ + 1: "queued", + 2: "completed", + 4: "errored", + } + + if states, err := db.GetStates(context.Background(), []int{1, 2, 4, 6}); err != nil { + t.Fatalf("unexpected error getting states: %s", err) + } else if diff := cmp.Diff(expected, states); diff != "" { + t.Errorf("unexpected upload states (-want +got):\n%s", diff) + } +} + +func TestDeleteUploadByID(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + insertUploads(t, db.db, + Upload{ID: 1}, + ) + + var called bool + getTipCommit := func(repositoryID int) (string, error) { + called = true + return "", nil + } + + if found, err := db.DeleteUploadByID(context.Background(), 1, getTipCommit); err != nil { + t.Fatalf("unexpected error deleting upload: %s", err) + } else if !found { + t.Fatalf("expected record to exist") + } else if called { + t.Fatalf("unexpected call to getTipCommit") + } + + // Upload no longer exists + if _, exists, err := db.GetUploadByID(context.Background(), 1); err != nil { + t.Fatalf("unexpected error getting upload: %s", err) + } else if exists { + t.Fatal("unexpected record") + } +} + +func TestDeleteUploadByIDMissingRow(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + getTipCommit := func(repositoryID int) (string, error) { + return "", nil + } + + if found, err := db.DeleteUploadByID(context.Background(), 1, getTipCommit); err != nil { + t.Fatalf("unexpected error deleting upload: %s", err) + } else if found { + t.Fatalf("unexpected record") + } +} + +func TestDeleteUploadByIDUpdatesVisibility(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + insertUploads(t, db.db, + Upload{ID: 1, Commit: makeCommit(4), Root: "sub1/", VisibleAtTip: true}, + Upload{ID: 2, Commit: makeCommit(3), Root: "sub2/", VisibleAtTip: true}, + Upload{ID: 3, Commit: makeCommit(2), Root: "sub1/", VisibleAtTip: false}, + Upload{ID: 4, Commit: makeCommit(1), Root: "sub2/", VisibleAtTip: false}, + ) + + insertCommits(t, db.db, map[string][]string{ + makeCommit(1): {}, + makeCommit(2): {makeCommit(1)}, + makeCommit(3): {makeCommit(2)}, + makeCommit(4): {makeCommit(3)}, + }) + + var called bool + getTipCommit := func(repositoryID int) (string, error) { + called = true + return makeCommit(4), nil + } + + if found, err := db.DeleteUploadByID(context.Background(), 1, getTipCommit); err != nil { + t.Fatalf("unexpected error deleting upload: %s", err) + } else if !found { + t.Fatalf("expected record to exist") + } else if !called { + t.Fatalf("expected call to getTipCommit") + } + + expected := map[int]bool{2: true, 3: true, 4: false} + visibilities := getDumpVisibilities(t, db.db) + if diff := cmp.Diff(expected, visibilities); diff != "" { + t.Errorf("unexpected visibility (-want +got):\n%s", diff) + } +} + +func TestResetStalled(t *testing.T) { + if testing.Short() { + t.Skip() + } + dbtesting.SetupGlobalTestDB(t) + db := &dbImpl{db: dbconn.Global} + + now := time.Unix(1587396557, 0).UTC() + t1 := now.Add(-time.Second * 6) // old + t2 := now.Add(-time.Second * 2) // new enough + t3 := now.Add(-time.Second * 3) // new enough + t4 := now.Add(-time.Second * 8) // old + t5 := now.Add(-time.Second * 8) // old + + insertUploads(t, db.db, + Upload{ID: 1, State: "processing", StartedAt: &t1}, + Upload{ID: 2, State: "processing", StartedAt: &t2}, + Upload{ID: 3, State: "processing", StartedAt: &t3}, + Upload{ID: 4, State: "processing", StartedAt: &t4}, + Upload{ID: 5, State: "processing", StartedAt: &t5}, + ) + + tx, err := db.db.BeginTx(context.Background(), nil) + if err != nil { + t.Fatal(err) + } + defer func() { _ = tx.Rollback() }() + + // Row lock upload 5 in a transaction which should be skipped by ResetStalled + if _, err := tx.Query(`SELECT * FROM lsif_uploads WHERE id = 5 FOR UPDATE`); err != nil { + t.Fatal(err) + } + + expected := []int{1, 4} + + if ids, err := db.ResetStalled(context.Background(), now); err != nil { + t.Fatalf("unexpected error resetting stalled uploads: %s", err) + } else if diff := cmp.Diff(expected, ids); diff != "" { + t.Errorf("unexpected ids (-want +got):\n%s", diff) + } +} diff --git a/cmd/precise-code-intel-api-server/internal/db/util.go b/cmd/precise-code-intel-api-server/internal/db/util.go new file mode 100644 index 00000000000..89d94267bb8 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/db/util.go @@ -0,0 +1,25 @@ +package db + +import ( + "database/sql" + + "github.com/keegancsmith/sqlf" +) + +// ignoreErrNoRows returns the given error if it's not sql.ErrNoRows. +func ignoreErrNoRows(err error) error { + if err == sql.ErrNoRows { + return nil + } + return err +} + +// intsToQueries converts a slice of ints into a slice of queries. +func intsToQueries(values []int) []*sqlf.Query { + var queries []*sqlf.Query + for _, value := range values { + queries = append(queries, sqlf.Sprintf("%d", value)) + } + + return queries +} diff --git a/cmd/precise-code-intel-api-server/internal/janitor/janitor.go b/cmd/precise-code-intel-api-server/internal/janitor/janitor.go new file mode 100644 index 00000000000..a00a3d3543c --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/janitor/janitor.go @@ -0,0 +1,68 @@ +package janitor + +import ( + "context" + "time" + + "github.com/inconshreveable/log15" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" +) + +type Janitor struct { + db db.DB + janitorInterval time.Duration +} + +type JanitorOpts struct { + DB db.DB + JanitorInterval time.Duration +} + +func NewJanitor(opts JanitorOpts) *Janitor { + return &Janitor{ + db: opts.DB, + janitorInterval: opts.JanitorInterval, + } +} + +func (j *Janitor) Start() { + for { + if err := j.step(); err != nil { + log15.Error("Failed to run janitor process", "error", err) + } + + time.Sleep(j.janitorInterval) + } +} + +// Run performs a best-effort cleanup. See the following methods for more specifics. +// - resetStalled +func (j *Janitor) step() error { + cleanupFns := []func() error{ + j.resetStalled, + } + + for _, fn := range cleanupFns { + if err := fn(); err != nil { + return err + } + } + + return nil +} + +// resetStalled moves all uploads that have been in the PROCESSING state for a while back +// to QUEUED. For each updated upload record, the conversion process that was responsible +// for handling the upload did not hold a row lock, indicating that it has died. +func (j *Janitor) resetStalled() error { + ids, err := j.db.ResetStalled(context.Background(), time.Now()) + if err != nil { + return err + } + + for _, id := range ids { + log15.Debug("Reset stalled upload", "uploadID", id) + } + + return nil +} diff --git a/cmd/precise-code-intel-api-server/internal/mocks/gen.go b/cmd/precise-code-intel-api-server/internal/mocks/gen.go new file mode 100644 index 00000000000..71e735862b5 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/mocks/gen.go @@ -0,0 +1,7 @@ +package mocks + +//go:generate env GOBIN=$PWD/.bin GO111MODULE=on go install github.com/efritz/go-mockgen +//go:generate $PWD/.bin/go-mockgen -f github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db -i DB -o mock_db.go +//go:generate $PWD/.bin/go-mockgen -f github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db -i ReferencePager -o mock_reference_pager.go +//go:generate $PWD/.bin/go-mockgen -f github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles -i BundleManagerClient -o mock_bundle_manager_client.go +//go:generate $PWD/.bin/go-mockgen -f github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles -i BundleClient -o mock_bundle_client.go diff --git a/cmd/precise-code-intel-api-server/internal/mocks/mock_bundle_client.go b/cmd/precise-code-intel-api-server/internal/mocks/mock_bundle_client.go new file mode 100644 index 00000000000..c3f0e32feb5 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/mocks/mock_bundle_client.go @@ -0,0 +1,921 @@ +// Code generated by github.com/efritz/go-mockgen 0.1.0; DO NOT EDIT. + +package mocks + +import ( + "context" + bundles "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" + "sync" +) + +// MockBundleClient is a mock impelementation of the BundleClient interface +// (from the package +// github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles) +// used for unit testing. +type MockBundleClient struct { + // DefinitionsFunc is an instance of a mock function object controlling + // the behavior of the method Definitions. + DefinitionsFunc *BundleClientDefinitionsFunc + // ExistsFunc is an instance of a mock function object controlling the + // behavior of the method Exists. + ExistsFunc *BundleClientExistsFunc + // HoverFunc is an instance of a mock function object controlling the + // behavior of the method Hover. + HoverFunc *BundleClientHoverFunc + // MonikerResultsFunc is an instance of a mock function object + // controlling the behavior of the method MonikerResults. + MonikerResultsFunc *BundleClientMonikerResultsFunc + // MonikersByPositionFunc is an instance of a mock function object + // controlling the behavior of the method MonikersByPosition. + MonikersByPositionFunc *BundleClientMonikersByPositionFunc + // PackageInformationFunc is an instance of a mock function object + // controlling the behavior of the method PackageInformation. + PackageInformationFunc *BundleClientPackageInformationFunc + // ReferencesFunc is an instance of a mock function object controlling + // the behavior of the method References. + ReferencesFunc *BundleClientReferencesFunc +} + +// NewMockBundleClient creates a new mock of the BundleClient interface. All +// methods return zero values for all results, unless overwritten. +func NewMockBundleClient() *MockBundleClient { + return &MockBundleClient{ + DefinitionsFunc: &BundleClientDefinitionsFunc{ + defaultHook: func(context.Context, string, int, int) ([]bundles.Location, error) { + return nil, nil + }, + }, + ExistsFunc: &BundleClientExistsFunc{ + defaultHook: func(context.Context, string) (bool, error) { + return false, nil + }, + }, + HoverFunc: &BundleClientHoverFunc{ + defaultHook: func(context.Context, string, int, int) (string, bundles.Range, bool, error) { + return "", bundles.Range{}, false, nil + }, + }, + MonikerResultsFunc: &BundleClientMonikerResultsFunc{ + defaultHook: func(context.Context, string, string, string, int, int) ([]bundles.Location, int, error) { + return nil, 0, nil + }, + }, + MonikersByPositionFunc: &BundleClientMonikersByPositionFunc{ + defaultHook: func(context.Context, string, int, int) ([][]bundles.MonikerData, error) { + return nil, nil + }, + }, + PackageInformationFunc: &BundleClientPackageInformationFunc{ + defaultHook: func(context.Context, string, string) (bundles.PackageInformationData, error) { + return bundles.PackageInformationData{}, nil + }, + }, + ReferencesFunc: &BundleClientReferencesFunc{ + defaultHook: func(context.Context, string, int, int) ([]bundles.Location, error) { + return nil, nil + }, + }, + } +} + +// NewMockBundleClientFrom creates a new mock of the MockBundleClient +// interface. All methods delegate to the given implementation, unless +// overwritten. +func NewMockBundleClientFrom(i bundles.BundleClient) *MockBundleClient { + return &MockBundleClient{ + DefinitionsFunc: &BundleClientDefinitionsFunc{ + defaultHook: i.Definitions, + }, + ExistsFunc: &BundleClientExistsFunc{ + defaultHook: i.Exists, + }, + HoverFunc: &BundleClientHoverFunc{ + defaultHook: i.Hover, + }, + MonikerResultsFunc: &BundleClientMonikerResultsFunc{ + defaultHook: i.MonikerResults, + }, + MonikersByPositionFunc: &BundleClientMonikersByPositionFunc{ + defaultHook: i.MonikersByPosition, + }, + PackageInformationFunc: &BundleClientPackageInformationFunc{ + defaultHook: i.PackageInformation, + }, + ReferencesFunc: &BundleClientReferencesFunc{ + defaultHook: i.References, + }, + } +} + +// BundleClientDefinitionsFunc describes the behavior when the Definitions +// method of the parent MockBundleClient instance is invoked. +type BundleClientDefinitionsFunc struct { + defaultHook func(context.Context, string, int, int) ([]bundles.Location, error) + hooks []func(context.Context, string, int, int) ([]bundles.Location, error) + history []BundleClientDefinitionsFuncCall + mutex sync.Mutex +} + +// Definitions delegates to the next hook function in the queue and stores +// the parameter and result values of this invocation. +func (m *MockBundleClient) Definitions(v0 context.Context, v1 string, v2 int, v3 int) ([]bundles.Location, error) { + r0, r1 := m.DefinitionsFunc.nextHook()(v0, v1, v2, v3) + m.DefinitionsFunc.appendCall(BundleClientDefinitionsFuncCall{v0, v1, v2, v3, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the Definitions method +// of the parent MockBundleClient instance is invoked and the hook queue is +// empty. +func (f *BundleClientDefinitionsFunc) SetDefaultHook(hook func(context.Context, string, int, int) ([]bundles.Location, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// Definitions method of the parent MockBundleClient instance inovkes the +// hook at the front of the queue and discards it. After the queue is empty, +// the default hook function is invoked for any future action. +func (f *BundleClientDefinitionsFunc) PushHook(hook func(context.Context, string, int, int) ([]bundles.Location, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *BundleClientDefinitionsFunc) SetDefaultReturn(r0 []bundles.Location, r1 error) { + f.SetDefaultHook(func(context.Context, string, int, int) ([]bundles.Location, error) { + return r0, r1 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *BundleClientDefinitionsFunc) PushReturn(r0 []bundles.Location, r1 error) { + f.PushHook(func(context.Context, string, int, int) ([]bundles.Location, error) { + return r0, r1 + }) +} + +func (f *BundleClientDefinitionsFunc) nextHook() func(context.Context, string, int, int) ([]bundles.Location, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *BundleClientDefinitionsFunc) appendCall(r0 BundleClientDefinitionsFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of BundleClientDefinitionsFuncCall objects +// describing the invocations of this function. +func (f *BundleClientDefinitionsFunc) History() []BundleClientDefinitionsFuncCall { + f.mutex.Lock() + history := make([]BundleClientDefinitionsFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// BundleClientDefinitionsFuncCall is an object that describes an invocation +// of method Definitions on an instance of MockBundleClient. +type BundleClientDefinitionsFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 string + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 int + // Arg3 is the value of the 4th argument passed to this method + // invocation. + Arg3 int + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 []bundles.Location + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c BundleClientDefinitionsFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c BundleClientDefinitionsFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// BundleClientExistsFunc describes the behavior when the Exists method of +// the parent MockBundleClient instance is invoked. +type BundleClientExistsFunc struct { + defaultHook func(context.Context, string) (bool, error) + hooks []func(context.Context, string) (bool, error) + history []BundleClientExistsFuncCall + mutex sync.Mutex +} + +// Exists delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockBundleClient) Exists(v0 context.Context, v1 string) (bool, error) { + r0, r1 := m.ExistsFunc.nextHook()(v0, v1) + m.ExistsFunc.appendCall(BundleClientExistsFuncCall{v0, v1, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the Exists method of the +// parent MockBundleClient instance is invoked and the hook queue is empty. +func (f *BundleClientExistsFunc) SetDefaultHook(hook func(context.Context, string) (bool, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// Exists method of the parent MockBundleClient instance inovkes the hook at +// the front of the queue and discards it. After the queue is empty, the +// default hook function is invoked for any future action. +func (f *BundleClientExistsFunc) PushHook(hook func(context.Context, string) (bool, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *BundleClientExistsFunc) SetDefaultReturn(r0 bool, r1 error) { + f.SetDefaultHook(func(context.Context, string) (bool, error) { + return r0, r1 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *BundleClientExistsFunc) PushReturn(r0 bool, r1 error) { + f.PushHook(func(context.Context, string) (bool, error) { + return r0, r1 + }) +} + +func (f *BundleClientExistsFunc) nextHook() func(context.Context, string) (bool, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *BundleClientExistsFunc) appendCall(r0 BundleClientExistsFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of BundleClientExistsFuncCall objects +// describing the invocations of this function. +func (f *BundleClientExistsFunc) History() []BundleClientExistsFuncCall { + f.mutex.Lock() + history := make([]BundleClientExistsFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// BundleClientExistsFuncCall is an object that describes an invocation of +// method Exists on an instance of MockBundleClient. +type BundleClientExistsFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 string + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 bool + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c BundleClientExistsFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c BundleClientExistsFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// BundleClientHoverFunc describes the behavior when the Hover method of the +// parent MockBundleClient instance is invoked. +type BundleClientHoverFunc struct { + defaultHook func(context.Context, string, int, int) (string, bundles.Range, bool, error) + hooks []func(context.Context, string, int, int) (string, bundles.Range, bool, error) + history []BundleClientHoverFuncCall + mutex sync.Mutex +} + +// Hover delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockBundleClient) Hover(v0 context.Context, v1 string, v2 int, v3 int) (string, bundles.Range, bool, error) { + r0, r1, r2, r3 := m.HoverFunc.nextHook()(v0, v1, v2, v3) + m.HoverFunc.appendCall(BundleClientHoverFuncCall{v0, v1, v2, v3, r0, r1, r2, r3}) + return r0, r1, r2, r3 +} + +// SetDefaultHook sets function that is called when the Hover method of the +// parent MockBundleClient instance is invoked and the hook queue is empty. +func (f *BundleClientHoverFunc) SetDefaultHook(hook func(context.Context, string, int, int) (string, bundles.Range, bool, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// Hover method of the parent MockBundleClient instance inovkes the hook at +// the front of the queue and discards it. After the queue is empty, the +// default hook function is invoked for any future action. +func (f *BundleClientHoverFunc) PushHook(hook func(context.Context, string, int, int) (string, bundles.Range, bool, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *BundleClientHoverFunc) SetDefaultReturn(r0 string, r1 bundles.Range, r2 bool, r3 error) { + f.SetDefaultHook(func(context.Context, string, int, int) (string, bundles.Range, bool, error) { + return r0, r1, r2, r3 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *BundleClientHoverFunc) PushReturn(r0 string, r1 bundles.Range, r2 bool, r3 error) { + f.PushHook(func(context.Context, string, int, int) (string, bundles.Range, bool, error) { + return r0, r1, r2, r3 + }) +} + +func (f *BundleClientHoverFunc) nextHook() func(context.Context, string, int, int) (string, bundles.Range, bool, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *BundleClientHoverFunc) appendCall(r0 BundleClientHoverFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of BundleClientHoverFuncCall objects +// describing the invocations of this function. +func (f *BundleClientHoverFunc) History() []BundleClientHoverFuncCall { + f.mutex.Lock() + history := make([]BundleClientHoverFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// BundleClientHoverFuncCall is an object that describes an invocation of +// method Hover on an instance of MockBundleClient. +type BundleClientHoverFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 string + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 int + // Arg3 is the value of the 4th argument passed to this method + // invocation. + Arg3 int + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 string + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 bundles.Range + // Result2 is the value of the 3rd result returned from this method + // invocation. + Result2 bool + // Result3 is the value of the 4th result returned from this method + // invocation. + Result3 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c BundleClientHoverFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c BundleClientHoverFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1, c.Result2, c.Result3} +} + +// BundleClientMonikerResultsFunc describes the behavior when the +// MonikerResults method of the parent MockBundleClient instance is invoked. +type BundleClientMonikerResultsFunc struct { + defaultHook func(context.Context, string, string, string, int, int) ([]bundles.Location, int, error) + hooks []func(context.Context, string, string, string, int, int) ([]bundles.Location, int, error) + history []BundleClientMonikerResultsFuncCall + mutex sync.Mutex +} + +// MonikerResults delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockBundleClient) MonikerResults(v0 context.Context, v1 string, v2 string, v3 string, v4 int, v5 int) ([]bundles.Location, int, error) { + r0, r1, r2 := m.MonikerResultsFunc.nextHook()(v0, v1, v2, v3, v4, v5) + m.MonikerResultsFunc.appendCall(BundleClientMonikerResultsFuncCall{v0, v1, v2, v3, v4, v5, r0, r1, r2}) + return r0, r1, r2 +} + +// SetDefaultHook sets function that is called when the MonikerResults +// method of the parent MockBundleClient instance is invoked and the hook +// queue is empty. +func (f *BundleClientMonikerResultsFunc) SetDefaultHook(hook func(context.Context, string, string, string, int, int) ([]bundles.Location, int, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// MonikerResults method of the parent MockBundleClient instance inovkes the +// hook at the front of the queue and discards it. After the queue is empty, +// the default hook function is invoked for any future action. +func (f *BundleClientMonikerResultsFunc) PushHook(hook func(context.Context, string, string, string, int, int) ([]bundles.Location, int, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *BundleClientMonikerResultsFunc) SetDefaultReturn(r0 []bundles.Location, r1 int, r2 error) { + f.SetDefaultHook(func(context.Context, string, string, string, int, int) ([]bundles.Location, int, error) { + return r0, r1, r2 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *BundleClientMonikerResultsFunc) PushReturn(r0 []bundles.Location, r1 int, r2 error) { + f.PushHook(func(context.Context, string, string, string, int, int) ([]bundles.Location, int, error) { + return r0, r1, r2 + }) +} + +func (f *BundleClientMonikerResultsFunc) nextHook() func(context.Context, string, string, string, int, int) ([]bundles.Location, int, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *BundleClientMonikerResultsFunc) appendCall(r0 BundleClientMonikerResultsFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of BundleClientMonikerResultsFuncCall objects +// describing the invocations of this function. +func (f *BundleClientMonikerResultsFunc) History() []BundleClientMonikerResultsFuncCall { + f.mutex.Lock() + history := make([]BundleClientMonikerResultsFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// BundleClientMonikerResultsFuncCall is an object that describes an +// invocation of method MonikerResults on an instance of MockBundleClient. +type BundleClientMonikerResultsFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 string + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 string + // Arg3 is the value of the 4th argument passed to this method + // invocation. + Arg3 string + // Arg4 is the value of the 5th argument passed to this method + // invocation. + Arg4 int + // Arg5 is the value of the 6th argument passed to this method + // invocation. + Arg5 int + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 []bundles.Location + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 int + // Result2 is the value of the 3rd result returned from this method + // invocation. + Result2 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c BundleClientMonikerResultsFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3, c.Arg4, c.Arg5} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c BundleClientMonikerResultsFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1, c.Result2} +} + +// BundleClientMonikersByPositionFunc describes the behavior when the +// MonikersByPosition method of the parent MockBundleClient instance is +// invoked. +type BundleClientMonikersByPositionFunc struct { + defaultHook func(context.Context, string, int, int) ([][]bundles.MonikerData, error) + hooks []func(context.Context, string, int, int) ([][]bundles.MonikerData, error) + history []BundleClientMonikersByPositionFuncCall + mutex sync.Mutex +} + +// MonikersByPosition delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockBundleClient) MonikersByPosition(v0 context.Context, v1 string, v2 int, v3 int) ([][]bundles.MonikerData, error) { + r0, r1 := m.MonikersByPositionFunc.nextHook()(v0, v1, v2, v3) + m.MonikersByPositionFunc.appendCall(BundleClientMonikersByPositionFuncCall{v0, v1, v2, v3, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the MonikersByPosition +// method of the parent MockBundleClient instance is invoked and the hook +// queue is empty. +func (f *BundleClientMonikersByPositionFunc) SetDefaultHook(hook func(context.Context, string, int, int) ([][]bundles.MonikerData, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// MonikersByPosition method of the parent MockBundleClient instance inovkes +// the hook at the front of the queue and discards it. After the queue is +// empty, the default hook function is invoked for any future action. +func (f *BundleClientMonikersByPositionFunc) PushHook(hook func(context.Context, string, int, int) ([][]bundles.MonikerData, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *BundleClientMonikersByPositionFunc) SetDefaultReturn(r0 [][]bundles.MonikerData, r1 error) { + f.SetDefaultHook(func(context.Context, string, int, int) ([][]bundles.MonikerData, error) { + return r0, r1 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *BundleClientMonikersByPositionFunc) PushReturn(r0 [][]bundles.MonikerData, r1 error) { + f.PushHook(func(context.Context, string, int, int) ([][]bundles.MonikerData, error) { + return r0, r1 + }) +} + +func (f *BundleClientMonikersByPositionFunc) nextHook() func(context.Context, string, int, int) ([][]bundles.MonikerData, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *BundleClientMonikersByPositionFunc) appendCall(r0 BundleClientMonikersByPositionFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of BundleClientMonikersByPositionFuncCall +// objects describing the invocations of this function. +func (f *BundleClientMonikersByPositionFunc) History() []BundleClientMonikersByPositionFuncCall { + f.mutex.Lock() + history := make([]BundleClientMonikersByPositionFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// BundleClientMonikersByPositionFuncCall is an object that describes an +// invocation of method MonikersByPosition on an instance of +// MockBundleClient. +type BundleClientMonikersByPositionFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 string + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 int + // Arg3 is the value of the 4th argument passed to this method + // invocation. + Arg3 int + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 [][]bundles.MonikerData + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c BundleClientMonikersByPositionFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c BundleClientMonikersByPositionFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// BundleClientPackageInformationFunc describes the behavior when the +// PackageInformation method of the parent MockBundleClient instance is +// invoked. +type BundleClientPackageInformationFunc struct { + defaultHook func(context.Context, string, string) (bundles.PackageInformationData, error) + hooks []func(context.Context, string, string) (bundles.PackageInformationData, error) + history []BundleClientPackageInformationFuncCall + mutex sync.Mutex +} + +// PackageInformation delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockBundleClient) PackageInformation(v0 context.Context, v1 string, v2 string) (bundles.PackageInformationData, error) { + r0, r1 := m.PackageInformationFunc.nextHook()(v0, v1, v2) + m.PackageInformationFunc.appendCall(BundleClientPackageInformationFuncCall{v0, v1, v2, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the PackageInformation +// method of the parent MockBundleClient instance is invoked and the hook +// queue is empty. +func (f *BundleClientPackageInformationFunc) SetDefaultHook(hook func(context.Context, string, string) (bundles.PackageInformationData, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// PackageInformation method of the parent MockBundleClient instance inovkes +// the hook at the front of the queue and discards it. After the queue is +// empty, the default hook function is invoked for any future action. +func (f *BundleClientPackageInformationFunc) PushHook(hook func(context.Context, string, string) (bundles.PackageInformationData, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *BundleClientPackageInformationFunc) SetDefaultReturn(r0 bundles.PackageInformationData, r1 error) { + f.SetDefaultHook(func(context.Context, string, string) (bundles.PackageInformationData, error) { + return r0, r1 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *BundleClientPackageInformationFunc) PushReturn(r0 bundles.PackageInformationData, r1 error) { + f.PushHook(func(context.Context, string, string) (bundles.PackageInformationData, error) { + return r0, r1 + }) +} + +func (f *BundleClientPackageInformationFunc) nextHook() func(context.Context, string, string) (bundles.PackageInformationData, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *BundleClientPackageInformationFunc) appendCall(r0 BundleClientPackageInformationFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of BundleClientPackageInformationFuncCall +// objects describing the invocations of this function. +func (f *BundleClientPackageInformationFunc) History() []BundleClientPackageInformationFuncCall { + f.mutex.Lock() + history := make([]BundleClientPackageInformationFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// BundleClientPackageInformationFuncCall is an object that describes an +// invocation of method PackageInformation on an instance of +// MockBundleClient. +type BundleClientPackageInformationFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 string + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 string + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 bundles.PackageInformationData + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c BundleClientPackageInformationFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c BundleClientPackageInformationFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// BundleClientReferencesFunc describes the behavior when the References +// method of the parent MockBundleClient instance is invoked. +type BundleClientReferencesFunc struct { + defaultHook func(context.Context, string, int, int) ([]bundles.Location, error) + hooks []func(context.Context, string, int, int) ([]bundles.Location, error) + history []BundleClientReferencesFuncCall + mutex sync.Mutex +} + +// References delegates to the next hook function in the queue and stores +// the parameter and result values of this invocation. +func (m *MockBundleClient) References(v0 context.Context, v1 string, v2 int, v3 int) ([]bundles.Location, error) { + r0, r1 := m.ReferencesFunc.nextHook()(v0, v1, v2, v3) + m.ReferencesFunc.appendCall(BundleClientReferencesFuncCall{v0, v1, v2, v3, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the References method of +// the parent MockBundleClient instance is invoked and the hook queue is +// empty. +func (f *BundleClientReferencesFunc) SetDefaultHook(hook func(context.Context, string, int, int) ([]bundles.Location, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// References method of the parent MockBundleClient instance inovkes the +// hook at the front of the queue and discards it. After the queue is empty, +// the default hook function is invoked for any future action. +func (f *BundleClientReferencesFunc) PushHook(hook func(context.Context, string, int, int) ([]bundles.Location, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *BundleClientReferencesFunc) SetDefaultReturn(r0 []bundles.Location, r1 error) { + f.SetDefaultHook(func(context.Context, string, int, int) ([]bundles.Location, error) { + return r0, r1 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *BundleClientReferencesFunc) PushReturn(r0 []bundles.Location, r1 error) { + f.PushHook(func(context.Context, string, int, int) ([]bundles.Location, error) { + return r0, r1 + }) +} + +func (f *BundleClientReferencesFunc) nextHook() func(context.Context, string, int, int) ([]bundles.Location, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *BundleClientReferencesFunc) appendCall(r0 BundleClientReferencesFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of BundleClientReferencesFuncCall objects +// describing the invocations of this function. +func (f *BundleClientReferencesFunc) History() []BundleClientReferencesFuncCall { + f.mutex.Lock() + history := make([]BundleClientReferencesFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// BundleClientReferencesFuncCall is an object that describes an invocation +// of method References on an instance of MockBundleClient. +type BundleClientReferencesFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 string + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 int + // Arg3 is the value of the 4th argument passed to this method + // invocation. + Arg3 int + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 []bundles.Location + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c BundleClientReferencesFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c BundleClientReferencesFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} diff --git a/cmd/precise-code-intel-api-server/internal/mocks/mock_bundle_manager_client.go b/cmd/precise-code-intel-api-server/internal/mocks/mock_bundle_manager_client.go new file mode 100644 index 00000000000..dd485b84455 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/mocks/mock_bundle_manager_client.go @@ -0,0 +1,272 @@ +// Code generated by github.com/efritz/go-mockgen 0.1.0; DO NOT EDIT. + +package mocks + +import ( + "context" + bundles "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" + "io" + "sync" +) + +// MockBundleManagerClient is a mock impelementation of the +// BundleManagerClient interface (from the package +// github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles) +// used for unit testing. +type MockBundleManagerClient struct { + // BundleClientFunc is an instance of a mock function object controlling + // the behavior of the method BundleClient. + BundleClientFunc *BundleManagerClientBundleClientFunc + // SendUploadFunc is an instance of a mock function object controlling + // the behavior of the method SendUpload. + SendUploadFunc *BundleManagerClientSendUploadFunc +} + +// NewMockBundleManagerClient creates a new mock of the BundleManagerClient +// interface. All methods return zero values for all results, unless +// overwritten. +func NewMockBundleManagerClient() *MockBundleManagerClient { + return &MockBundleManagerClient{ + BundleClientFunc: &BundleManagerClientBundleClientFunc{ + defaultHook: func(int) bundles.BundleClient { + return nil + }, + }, + SendUploadFunc: &BundleManagerClientSendUploadFunc{ + defaultHook: func(context.Context, int, io.Reader) error { + return nil + }, + }, + } +} + +// NewMockBundleManagerClientFrom creates a new mock of the +// MockBundleManagerClient interface. All methods delegate to the given +// implementation, unless overwritten. +func NewMockBundleManagerClientFrom(i bundles.BundleManagerClient) *MockBundleManagerClient { + return &MockBundleManagerClient{ + BundleClientFunc: &BundleManagerClientBundleClientFunc{ + defaultHook: i.BundleClient, + }, + SendUploadFunc: &BundleManagerClientSendUploadFunc{ + defaultHook: i.SendUpload, + }, + } +} + +// BundleManagerClientBundleClientFunc describes the behavior when the +// BundleClient method of the parent MockBundleManagerClient instance is +// invoked. +type BundleManagerClientBundleClientFunc struct { + defaultHook func(int) bundles.BundleClient + hooks []func(int) bundles.BundleClient + history []BundleManagerClientBundleClientFuncCall + mutex sync.Mutex +} + +// BundleClient delegates to the next hook function in the queue and stores +// the parameter and result values of this invocation. +func (m *MockBundleManagerClient) BundleClient(v0 int) bundles.BundleClient { + r0 := m.BundleClientFunc.nextHook()(v0) + m.BundleClientFunc.appendCall(BundleManagerClientBundleClientFuncCall{v0, r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the BundleClient method +// of the parent MockBundleManagerClient instance is invoked and the hook +// queue is empty. +func (f *BundleManagerClientBundleClientFunc) SetDefaultHook(hook func(int) bundles.BundleClient) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// BundleClient method of the parent MockBundleManagerClient instance +// inovkes the hook at the front of the queue and discards it. After the +// queue is empty, the default hook function is invoked for any future +// action. +func (f *BundleManagerClientBundleClientFunc) PushHook(hook func(int) bundles.BundleClient) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *BundleManagerClientBundleClientFunc) SetDefaultReturn(r0 bundles.BundleClient) { + f.SetDefaultHook(func(int) bundles.BundleClient { + return r0 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *BundleManagerClientBundleClientFunc) PushReturn(r0 bundles.BundleClient) { + f.PushHook(func(int) bundles.BundleClient { + return r0 + }) +} + +func (f *BundleManagerClientBundleClientFunc) nextHook() func(int) bundles.BundleClient { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *BundleManagerClientBundleClientFunc) appendCall(r0 BundleManagerClientBundleClientFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of BundleManagerClientBundleClientFuncCall +// objects describing the invocations of this function. +func (f *BundleManagerClientBundleClientFunc) History() []BundleManagerClientBundleClientFuncCall { + f.mutex.Lock() + history := make([]BundleManagerClientBundleClientFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// BundleManagerClientBundleClientFuncCall is an object that describes an +// invocation of method BundleClient on an instance of +// MockBundleManagerClient. +type BundleManagerClientBundleClientFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 int + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 bundles.BundleClient +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c BundleManagerClientBundleClientFuncCall) Args() []interface{} { + return []interface{}{c.Arg0} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c BundleManagerClientBundleClientFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} + +// BundleManagerClientSendUploadFunc describes the behavior when the +// SendUpload method of the parent MockBundleManagerClient instance is +// invoked. +type BundleManagerClientSendUploadFunc struct { + defaultHook func(context.Context, int, io.Reader) error + hooks []func(context.Context, int, io.Reader) error + history []BundleManagerClientSendUploadFuncCall + mutex sync.Mutex +} + +// SendUpload delegates to the next hook function in the queue and stores +// the parameter and result values of this invocation. +func (m *MockBundleManagerClient) SendUpload(v0 context.Context, v1 int, v2 io.Reader) error { + r0 := m.SendUploadFunc.nextHook()(v0, v1, v2) + m.SendUploadFunc.appendCall(BundleManagerClientSendUploadFuncCall{v0, v1, v2, r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the SendUpload method of +// the parent MockBundleManagerClient instance is invoked and the hook queue +// is empty. +func (f *BundleManagerClientSendUploadFunc) SetDefaultHook(hook func(context.Context, int, io.Reader) error) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// SendUpload method of the parent MockBundleManagerClient instance inovkes +// the hook at the front of the queue and discards it. After the queue is +// empty, the default hook function is invoked for any future action. +func (f *BundleManagerClientSendUploadFunc) PushHook(hook func(context.Context, int, io.Reader) error) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *BundleManagerClientSendUploadFunc) SetDefaultReturn(r0 error) { + f.SetDefaultHook(func(context.Context, int, io.Reader) error { + return r0 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *BundleManagerClientSendUploadFunc) PushReturn(r0 error) { + f.PushHook(func(context.Context, int, io.Reader) error { + return r0 + }) +} + +func (f *BundleManagerClientSendUploadFunc) nextHook() func(context.Context, int, io.Reader) error { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *BundleManagerClientSendUploadFunc) appendCall(r0 BundleManagerClientSendUploadFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of BundleManagerClientSendUploadFuncCall +// objects describing the invocations of this function. +func (f *BundleManagerClientSendUploadFunc) History() []BundleManagerClientSendUploadFuncCall { + f.mutex.Lock() + history := make([]BundleManagerClientSendUploadFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// BundleManagerClientSendUploadFuncCall is an object that describes an +// invocation of method SendUpload on an instance of +// MockBundleManagerClient. +type BundleManagerClientSendUploadFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 int + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 io.Reader + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c BundleManagerClientSendUploadFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c BundleManagerClientSendUploadFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} diff --git a/cmd/precise-code-intel-api-server/internal/mocks/mock_db.go b/cmd/precise-code-intel-api-server/internal/mocks/mock_db.go new file mode 100644 index 00000000000..355e8d6a1fc --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/mocks/mock_db.go @@ -0,0 +1,1553 @@ +// Code generated by github.com/efritz/go-mockgen 0.1.0; DO NOT EDIT. + +package mocks + +import ( + "context" + db "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" + "sync" + "time" +) + +// MockDB is a mock impelementation of the DB interface (from the package +// github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db) +// used for unit testing. +type MockDB struct { + // DeleteOldestDumpFunc is an instance of a mock function object + // controlling the behavior of the method DeleteOldestDump. + DeleteOldestDumpFunc *DBDeleteOldestDumpFunc + // DeleteUploadByIDFunc is an instance of a mock function object + // controlling the behavior of the method DeleteUploadByID. + DeleteUploadByIDFunc *DBDeleteUploadByIDFunc + // EnqueueFunc is an instance of a mock function object controlling the + // behavior of the method Enqueue. + EnqueueFunc *DBEnqueueFunc + // FindClosestDumpsFunc is an instance of a mock function object + // controlling the behavior of the method FindClosestDumps. + FindClosestDumpsFunc *DBFindClosestDumpsFunc + // GetDumpByIDFunc is an instance of a mock function object controlling + // the behavior of the method GetDumpByID. + GetDumpByIDFunc *DBGetDumpByIDFunc + // GetPackageFunc is an instance of a mock function object controlling + // the behavior of the method GetPackage. + GetPackageFunc *DBGetPackageFunc + // GetStatesFunc is an instance of a mock function object controlling + // the behavior of the method GetStates. + GetStatesFunc *DBGetStatesFunc + // GetUploadByIDFunc is an instance of a mock function object + // controlling the behavior of the method GetUploadByID. + GetUploadByIDFunc *DBGetUploadByIDFunc + // GetUploadsByRepoFunc is an instance of a mock function object + // controlling the behavior of the method GetUploadsByRepo. + GetUploadsByRepoFunc *DBGetUploadsByRepoFunc + // PackageReferencePagerFunc is an instance of a mock function object + // controlling the behavior of the method PackageReferencePager. + PackageReferencePagerFunc *DBPackageReferencePagerFunc + // ResetStalledFunc is an instance of a mock function object controlling + // the behavior of the method ResetStalled. + ResetStalledFunc *DBResetStalledFunc + // SameRepoPagerFunc is an instance of a mock function object + // controlling the behavior of the method SameRepoPager. + SameRepoPagerFunc *DBSameRepoPagerFunc +} + +// NewMockDB creates a new mock of the DB interface. All methods return zero +// values for all results, unless overwritten. +func NewMockDB() *MockDB { + return &MockDB{ + DeleteOldestDumpFunc: &DBDeleteOldestDumpFunc{ + defaultHook: func(context.Context) (int, bool, error) { + return 0, false, nil + }, + }, + DeleteUploadByIDFunc: &DBDeleteUploadByIDFunc{ + defaultHook: func(context.Context, int, func(repositoryID int) (string, error)) (bool, error) { + return false, nil + }, + }, + EnqueueFunc: &DBEnqueueFunc{ + defaultHook: func(context.Context, string, string, string, int, string) (int, db.TxCloser, error) { + return 0, nil, nil + }, + }, + FindClosestDumpsFunc: &DBFindClosestDumpsFunc{ + defaultHook: func(context.Context, int, string, string) ([]db.Dump, error) { + return nil, nil + }, + }, + GetDumpByIDFunc: &DBGetDumpByIDFunc{ + defaultHook: func(context.Context, int) (db.Dump, bool, error) { + return db.Dump{}, false, nil + }, + }, + GetPackageFunc: &DBGetPackageFunc{ + defaultHook: func(context.Context, string, string, string) (db.Dump, bool, error) { + return db.Dump{}, false, nil + }, + }, + GetStatesFunc: &DBGetStatesFunc{ + defaultHook: func(context.Context, []int) (map[int]string, error) { + return nil, nil + }, + }, + GetUploadByIDFunc: &DBGetUploadByIDFunc{ + defaultHook: func(context.Context, int) (db.Upload, bool, error) { + return db.Upload{}, false, nil + }, + }, + GetUploadsByRepoFunc: &DBGetUploadsByRepoFunc{ + defaultHook: func(context.Context, int, string, string, bool, int, int) ([]db.Upload, int, error) { + return nil, 0, nil + }, + }, + PackageReferencePagerFunc: &DBPackageReferencePagerFunc{ + defaultHook: func(context.Context, string, string, string, int, int) (int, db.ReferencePager, error) { + return 0, nil, nil + }, + }, + ResetStalledFunc: &DBResetStalledFunc{ + defaultHook: func(context.Context, time.Time) ([]int, error) { + return nil, nil + }, + }, + SameRepoPagerFunc: &DBSameRepoPagerFunc{ + defaultHook: func(context.Context, int, string, string, string, string, int) (int, db.ReferencePager, error) { + return 0, nil, nil + }, + }, + } +} + +// NewMockDBFrom creates a new mock of the MockDB interface. All methods +// delegate to the given implementation, unless overwritten. +func NewMockDBFrom(i db.DB) *MockDB { + return &MockDB{ + DeleteOldestDumpFunc: &DBDeleteOldestDumpFunc{ + defaultHook: i.DeleteOldestDump, + }, + DeleteUploadByIDFunc: &DBDeleteUploadByIDFunc{ + defaultHook: i.DeleteUploadByID, + }, + EnqueueFunc: &DBEnqueueFunc{ + defaultHook: i.Enqueue, + }, + FindClosestDumpsFunc: &DBFindClosestDumpsFunc{ + defaultHook: i.FindClosestDumps, + }, + GetDumpByIDFunc: &DBGetDumpByIDFunc{ + defaultHook: i.GetDumpByID, + }, + GetPackageFunc: &DBGetPackageFunc{ + defaultHook: i.GetPackage, + }, + GetStatesFunc: &DBGetStatesFunc{ + defaultHook: i.GetStates, + }, + GetUploadByIDFunc: &DBGetUploadByIDFunc{ + defaultHook: i.GetUploadByID, + }, + GetUploadsByRepoFunc: &DBGetUploadsByRepoFunc{ + defaultHook: i.GetUploadsByRepo, + }, + PackageReferencePagerFunc: &DBPackageReferencePagerFunc{ + defaultHook: i.PackageReferencePager, + }, + ResetStalledFunc: &DBResetStalledFunc{ + defaultHook: i.ResetStalled, + }, + SameRepoPagerFunc: &DBSameRepoPagerFunc{ + defaultHook: i.SameRepoPager, + }, + } +} + +// DBDeleteOldestDumpFunc describes the behavior when the DeleteOldestDump +// method of the parent MockDB instance is invoked. +type DBDeleteOldestDumpFunc struct { + defaultHook func(context.Context) (int, bool, error) + hooks []func(context.Context) (int, bool, error) + history []DBDeleteOldestDumpFuncCall + mutex sync.Mutex +} + +// DeleteOldestDump delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockDB) DeleteOldestDump(v0 context.Context) (int, bool, error) { + r0, r1, r2 := m.DeleteOldestDumpFunc.nextHook()(v0) + m.DeleteOldestDumpFunc.appendCall(DBDeleteOldestDumpFuncCall{v0, r0, r1, r2}) + return r0, r1, r2 +} + +// SetDefaultHook sets function that is called when the DeleteOldestDump +// method of the parent MockDB instance is invoked and the hook queue is +// empty. +func (f *DBDeleteOldestDumpFunc) SetDefaultHook(hook func(context.Context) (int, bool, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// DeleteOldestDump method of the parent MockDB instance inovkes the hook at +// the front of the queue and discards it. After the queue is empty, the +// default hook function is invoked for any future action. +func (f *DBDeleteOldestDumpFunc) PushHook(hook func(context.Context) (int, bool, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *DBDeleteOldestDumpFunc) SetDefaultReturn(r0 int, r1 bool, r2 error) { + f.SetDefaultHook(func(context.Context) (int, bool, error) { + return r0, r1, r2 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *DBDeleteOldestDumpFunc) PushReturn(r0 int, r1 bool, r2 error) { + f.PushHook(func(context.Context) (int, bool, error) { + return r0, r1, r2 + }) +} + +func (f *DBDeleteOldestDumpFunc) nextHook() func(context.Context) (int, bool, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *DBDeleteOldestDumpFunc) appendCall(r0 DBDeleteOldestDumpFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of DBDeleteOldestDumpFuncCall objects +// describing the invocations of this function. +func (f *DBDeleteOldestDumpFunc) History() []DBDeleteOldestDumpFuncCall { + f.mutex.Lock() + history := make([]DBDeleteOldestDumpFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// DBDeleteOldestDumpFuncCall is an object that describes an invocation of +// method DeleteOldestDump on an instance of MockDB. +type DBDeleteOldestDumpFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 int + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 bool + // Result2 is the value of the 3rd result returned from this method + // invocation. + Result2 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c DBDeleteOldestDumpFuncCall) Args() []interface{} { + return []interface{}{c.Arg0} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c DBDeleteOldestDumpFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1, c.Result2} +} + +// DBDeleteUploadByIDFunc describes the behavior when the DeleteUploadByID +// method of the parent MockDB instance is invoked. +type DBDeleteUploadByIDFunc struct { + defaultHook func(context.Context, int, func(repositoryID int) (string, error)) (bool, error) + hooks []func(context.Context, int, func(repositoryID int) (string, error)) (bool, error) + history []DBDeleteUploadByIDFuncCall + mutex sync.Mutex +} + +// DeleteUploadByID delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockDB) DeleteUploadByID(v0 context.Context, v1 int, v2 func(repositoryID int) (string, error)) (bool, error) { + r0, r1 := m.DeleteUploadByIDFunc.nextHook()(v0, v1, v2) + m.DeleteUploadByIDFunc.appendCall(DBDeleteUploadByIDFuncCall{v0, v1, v2, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the DeleteUploadByID +// method of the parent MockDB instance is invoked and the hook queue is +// empty. +func (f *DBDeleteUploadByIDFunc) SetDefaultHook(hook func(context.Context, int, func(repositoryID int) (string, error)) (bool, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// DeleteUploadByID method of the parent MockDB instance inovkes the hook at +// the front of the queue and discards it. After the queue is empty, the +// default hook function is invoked for any future action. +func (f *DBDeleteUploadByIDFunc) PushHook(hook func(context.Context, int, func(repositoryID int) (string, error)) (bool, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *DBDeleteUploadByIDFunc) SetDefaultReturn(r0 bool, r1 error) { + f.SetDefaultHook(func(context.Context, int, func(repositoryID int) (string, error)) (bool, error) { + return r0, r1 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *DBDeleteUploadByIDFunc) PushReturn(r0 bool, r1 error) { + f.PushHook(func(context.Context, int, func(repositoryID int) (string, error)) (bool, error) { + return r0, r1 + }) +} + +func (f *DBDeleteUploadByIDFunc) nextHook() func(context.Context, int, func(repositoryID int) (string, error)) (bool, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *DBDeleteUploadByIDFunc) appendCall(r0 DBDeleteUploadByIDFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of DBDeleteUploadByIDFuncCall objects +// describing the invocations of this function. +func (f *DBDeleteUploadByIDFunc) History() []DBDeleteUploadByIDFuncCall { + f.mutex.Lock() + history := make([]DBDeleteUploadByIDFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// DBDeleteUploadByIDFuncCall is an object that describes an invocation of +// method DeleteUploadByID on an instance of MockDB. +type DBDeleteUploadByIDFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 int + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 func(repositoryID int) (string, error) + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 bool + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c DBDeleteUploadByIDFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c DBDeleteUploadByIDFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// DBEnqueueFunc describes the behavior when the Enqueue method of the +// parent MockDB instance is invoked. +type DBEnqueueFunc struct { + defaultHook func(context.Context, string, string, string, int, string) (int, db.TxCloser, error) + hooks []func(context.Context, string, string, string, int, string) (int, db.TxCloser, error) + history []DBEnqueueFuncCall + mutex sync.Mutex +} + +// Enqueue delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockDB) Enqueue(v0 context.Context, v1 string, v2 string, v3 string, v4 int, v5 string) (int, db.TxCloser, error) { + r0, r1, r2 := m.EnqueueFunc.nextHook()(v0, v1, v2, v3, v4, v5) + m.EnqueueFunc.appendCall(DBEnqueueFuncCall{v0, v1, v2, v3, v4, v5, r0, r1, r2}) + return r0, r1, r2 +} + +// SetDefaultHook sets function that is called when the Enqueue method of +// the parent MockDB instance is invoked and the hook queue is empty. +func (f *DBEnqueueFunc) SetDefaultHook(hook func(context.Context, string, string, string, int, string) (int, db.TxCloser, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// Enqueue method of the parent MockDB instance inovkes the hook at the +// front of the queue and discards it. After the queue is empty, the default +// hook function is invoked for any future action. +func (f *DBEnqueueFunc) PushHook(hook func(context.Context, string, string, string, int, string) (int, db.TxCloser, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *DBEnqueueFunc) SetDefaultReturn(r0 int, r1 db.TxCloser, r2 error) { + f.SetDefaultHook(func(context.Context, string, string, string, int, string) (int, db.TxCloser, error) { + return r0, r1, r2 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *DBEnqueueFunc) PushReturn(r0 int, r1 db.TxCloser, r2 error) { + f.PushHook(func(context.Context, string, string, string, int, string) (int, db.TxCloser, error) { + return r0, r1, r2 + }) +} + +func (f *DBEnqueueFunc) nextHook() func(context.Context, string, string, string, int, string) (int, db.TxCloser, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *DBEnqueueFunc) appendCall(r0 DBEnqueueFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of DBEnqueueFuncCall objects describing the +// invocations of this function. +func (f *DBEnqueueFunc) History() []DBEnqueueFuncCall { + f.mutex.Lock() + history := make([]DBEnqueueFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// DBEnqueueFuncCall is an object that describes an invocation of method +// Enqueue on an instance of MockDB. +type DBEnqueueFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 string + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 string + // Arg3 is the value of the 4th argument passed to this method + // invocation. + Arg3 string + // Arg4 is the value of the 5th argument passed to this method + // invocation. + Arg4 int + // Arg5 is the value of the 6th argument passed to this method + // invocation. + Arg5 string + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 int + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 db.TxCloser + // Result2 is the value of the 3rd result returned from this method + // invocation. + Result2 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c DBEnqueueFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3, c.Arg4, c.Arg5} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c DBEnqueueFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1, c.Result2} +} + +// DBFindClosestDumpsFunc describes the behavior when the FindClosestDumps +// method of the parent MockDB instance is invoked. +type DBFindClosestDumpsFunc struct { + defaultHook func(context.Context, int, string, string) ([]db.Dump, error) + hooks []func(context.Context, int, string, string) ([]db.Dump, error) + history []DBFindClosestDumpsFuncCall + mutex sync.Mutex +} + +// FindClosestDumps delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockDB) FindClosestDumps(v0 context.Context, v1 int, v2 string, v3 string) ([]db.Dump, error) { + r0, r1 := m.FindClosestDumpsFunc.nextHook()(v0, v1, v2, v3) + m.FindClosestDumpsFunc.appendCall(DBFindClosestDumpsFuncCall{v0, v1, v2, v3, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the FindClosestDumps +// method of the parent MockDB instance is invoked and the hook queue is +// empty. +func (f *DBFindClosestDumpsFunc) SetDefaultHook(hook func(context.Context, int, string, string) ([]db.Dump, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// FindClosestDumps method of the parent MockDB instance inovkes the hook at +// the front of the queue and discards it. After the queue is empty, the +// default hook function is invoked for any future action. +func (f *DBFindClosestDumpsFunc) PushHook(hook func(context.Context, int, string, string) ([]db.Dump, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *DBFindClosestDumpsFunc) SetDefaultReturn(r0 []db.Dump, r1 error) { + f.SetDefaultHook(func(context.Context, int, string, string) ([]db.Dump, error) { + return r0, r1 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *DBFindClosestDumpsFunc) PushReturn(r0 []db.Dump, r1 error) { + f.PushHook(func(context.Context, int, string, string) ([]db.Dump, error) { + return r0, r1 + }) +} + +func (f *DBFindClosestDumpsFunc) nextHook() func(context.Context, int, string, string) ([]db.Dump, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *DBFindClosestDumpsFunc) appendCall(r0 DBFindClosestDumpsFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of DBFindClosestDumpsFuncCall objects +// describing the invocations of this function. +func (f *DBFindClosestDumpsFunc) History() []DBFindClosestDumpsFuncCall { + f.mutex.Lock() + history := make([]DBFindClosestDumpsFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// DBFindClosestDumpsFuncCall is an object that describes an invocation of +// method FindClosestDumps on an instance of MockDB. +type DBFindClosestDumpsFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 int + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 string + // Arg3 is the value of the 4th argument passed to this method + // invocation. + Arg3 string + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 []db.Dump + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c DBFindClosestDumpsFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c DBFindClosestDumpsFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// DBGetDumpByIDFunc describes the behavior when the GetDumpByID method of +// the parent MockDB instance is invoked. +type DBGetDumpByIDFunc struct { + defaultHook func(context.Context, int) (db.Dump, bool, error) + hooks []func(context.Context, int) (db.Dump, bool, error) + history []DBGetDumpByIDFuncCall + mutex sync.Mutex +} + +// GetDumpByID delegates to the next hook function in the queue and stores +// the parameter and result values of this invocation. +func (m *MockDB) GetDumpByID(v0 context.Context, v1 int) (db.Dump, bool, error) { + r0, r1, r2 := m.GetDumpByIDFunc.nextHook()(v0, v1) + m.GetDumpByIDFunc.appendCall(DBGetDumpByIDFuncCall{v0, v1, r0, r1, r2}) + return r0, r1, r2 +} + +// SetDefaultHook sets function that is called when the GetDumpByID method +// of the parent MockDB instance is invoked and the hook queue is empty. +func (f *DBGetDumpByIDFunc) SetDefaultHook(hook func(context.Context, int) (db.Dump, bool, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// GetDumpByID method of the parent MockDB instance inovkes the hook at the +// front of the queue and discards it. After the queue is empty, the default +// hook function is invoked for any future action. +func (f *DBGetDumpByIDFunc) PushHook(hook func(context.Context, int) (db.Dump, bool, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *DBGetDumpByIDFunc) SetDefaultReturn(r0 db.Dump, r1 bool, r2 error) { + f.SetDefaultHook(func(context.Context, int) (db.Dump, bool, error) { + return r0, r1, r2 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *DBGetDumpByIDFunc) PushReturn(r0 db.Dump, r1 bool, r2 error) { + f.PushHook(func(context.Context, int) (db.Dump, bool, error) { + return r0, r1, r2 + }) +} + +func (f *DBGetDumpByIDFunc) nextHook() func(context.Context, int) (db.Dump, bool, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *DBGetDumpByIDFunc) appendCall(r0 DBGetDumpByIDFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of DBGetDumpByIDFuncCall objects describing +// the invocations of this function. +func (f *DBGetDumpByIDFunc) History() []DBGetDumpByIDFuncCall { + f.mutex.Lock() + history := make([]DBGetDumpByIDFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// DBGetDumpByIDFuncCall is an object that describes an invocation of method +// GetDumpByID on an instance of MockDB. +type DBGetDumpByIDFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 int + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 db.Dump + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 bool + // Result2 is the value of the 3rd result returned from this method + // invocation. + Result2 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c DBGetDumpByIDFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c DBGetDumpByIDFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1, c.Result2} +} + +// DBGetPackageFunc describes the behavior when the GetPackage method of the +// parent MockDB instance is invoked. +type DBGetPackageFunc struct { + defaultHook func(context.Context, string, string, string) (db.Dump, bool, error) + hooks []func(context.Context, string, string, string) (db.Dump, bool, error) + history []DBGetPackageFuncCall + mutex sync.Mutex +} + +// GetPackage delegates to the next hook function in the queue and stores +// the parameter and result values of this invocation. +func (m *MockDB) GetPackage(v0 context.Context, v1 string, v2 string, v3 string) (db.Dump, bool, error) { + r0, r1, r2 := m.GetPackageFunc.nextHook()(v0, v1, v2, v3) + m.GetPackageFunc.appendCall(DBGetPackageFuncCall{v0, v1, v2, v3, r0, r1, r2}) + return r0, r1, r2 +} + +// SetDefaultHook sets function that is called when the GetPackage method of +// the parent MockDB instance is invoked and the hook queue is empty. +func (f *DBGetPackageFunc) SetDefaultHook(hook func(context.Context, string, string, string) (db.Dump, bool, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// GetPackage method of the parent MockDB instance inovkes the hook at the +// front of the queue and discards it. After the queue is empty, the default +// hook function is invoked for any future action. +func (f *DBGetPackageFunc) PushHook(hook func(context.Context, string, string, string) (db.Dump, bool, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *DBGetPackageFunc) SetDefaultReturn(r0 db.Dump, r1 bool, r2 error) { + f.SetDefaultHook(func(context.Context, string, string, string) (db.Dump, bool, error) { + return r0, r1, r2 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *DBGetPackageFunc) PushReturn(r0 db.Dump, r1 bool, r2 error) { + f.PushHook(func(context.Context, string, string, string) (db.Dump, bool, error) { + return r0, r1, r2 + }) +} + +func (f *DBGetPackageFunc) nextHook() func(context.Context, string, string, string) (db.Dump, bool, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *DBGetPackageFunc) appendCall(r0 DBGetPackageFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of DBGetPackageFuncCall objects describing the +// invocations of this function. +func (f *DBGetPackageFunc) History() []DBGetPackageFuncCall { + f.mutex.Lock() + history := make([]DBGetPackageFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// DBGetPackageFuncCall is an object that describes an invocation of method +// GetPackage on an instance of MockDB. +type DBGetPackageFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 string + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 string + // Arg3 is the value of the 4th argument passed to this method + // invocation. + Arg3 string + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 db.Dump + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 bool + // Result2 is the value of the 3rd result returned from this method + // invocation. + Result2 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c DBGetPackageFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c DBGetPackageFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1, c.Result2} +} + +// DBGetStatesFunc describes the behavior when the GetStates method of the +// parent MockDB instance is invoked. +type DBGetStatesFunc struct { + defaultHook func(context.Context, []int) (map[int]string, error) + hooks []func(context.Context, []int) (map[int]string, error) + history []DBGetStatesFuncCall + mutex sync.Mutex +} + +// GetStates delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockDB) GetStates(v0 context.Context, v1 []int) (map[int]string, error) { + r0, r1 := m.GetStatesFunc.nextHook()(v0, v1) + m.GetStatesFunc.appendCall(DBGetStatesFuncCall{v0, v1, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the GetStates method of +// the parent MockDB instance is invoked and the hook queue is empty. +func (f *DBGetStatesFunc) SetDefaultHook(hook func(context.Context, []int) (map[int]string, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// GetStates method of the parent MockDB instance inovkes the hook at the +// front of the queue and discards it. After the queue is empty, the default +// hook function is invoked for any future action. +func (f *DBGetStatesFunc) PushHook(hook func(context.Context, []int) (map[int]string, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *DBGetStatesFunc) SetDefaultReturn(r0 map[int]string, r1 error) { + f.SetDefaultHook(func(context.Context, []int) (map[int]string, error) { + return r0, r1 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *DBGetStatesFunc) PushReturn(r0 map[int]string, r1 error) { + f.PushHook(func(context.Context, []int) (map[int]string, error) { + return r0, r1 + }) +} + +func (f *DBGetStatesFunc) nextHook() func(context.Context, []int) (map[int]string, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *DBGetStatesFunc) appendCall(r0 DBGetStatesFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of DBGetStatesFuncCall objects describing the +// invocations of this function. +func (f *DBGetStatesFunc) History() []DBGetStatesFuncCall { + f.mutex.Lock() + history := make([]DBGetStatesFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// DBGetStatesFuncCall is an object that describes an invocation of method +// GetStates on an instance of MockDB. +type DBGetStatesFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 []int + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 map[int]string + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c DBGetStatesFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c DBGetStatesFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// DBGetUploadByIDFunc describes the behavior when the GetUploadByID method +// of the parent MockDB instance is invoked. +type DBGetUploadByIDFunc struct { + defaultHook func(context.Context, int) (db.Upload, bool, error) + hooks []func(context.Context, int) (db.Upload, bool, error) + history []DBGetUploadByIDFuncCall + mutex sync.Mutex +} + +// GetUploadByID delegates to the next hook function in the queue and stores +// the parameter and result values of this invocation. +func (m *MockDB) GetUploadByID(v0 context.Context, v1 int) (db.Upload, bool, error) { + r0, r1, r2 := m.GetUploadByIDFunc.nextHook()(v0, v1) + m.GetUploadByIDFunc.appendCall(DBGetUploadByIDFuncCall{v0, v1, r0, r1, r2}) + return r0, r1, r2 +} + +// SetDefaultHook sets function that is called when the GetUploadByID method +// of the parent MockDB instance is invoked and the hook queue is empty. +func (f *DBGetUploadByIDFunc) SetDefaultHook(hook func(context.Context, int) (db.Upload, bool, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// GetUploadByID method of the parent MockDB instance inovkes the hook at +// the front of the queue and discards it. After the queue is empty, the +// default hook function is invoked for any future action. +func (f *DBGetUploadByIDFunc) PushHook(hook func(context.Context, int) (db.Upload, bool, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *DBGetUploadByIDFunc) SetDefaultReturn(r0 db.Upload, r1 bool, r2 error) { + f.SetDefaultHook(func(context.Context, int) (db.Upload, bool, error) { + return r0, r1, r2 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *DBGetUploadByIDFunc) PushReturn(r0 db.Upload, r1 bool, r2 error) { + f.PushHook(func(context.Context, int) (db.Upload, bool, error) { + return r0, r1, r2 + }) +} + +func (f *DBGetUploadByIDFunc) nextHook() func(context.Context, int) (db.Upload, bool, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *DBGetUploadByIDFunc) appendCall(r0 DBGetUploadByIDFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of DBGetUploadByIDFuncCall objects describing +// the invocations of this function. +func (f *DBGetUploadByIDFunc) History() []DBGetUploadByIDFuncCall { + f.mutex.Lock() + history := make([]DBGetUploadByIDFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// DBGetUploadByIDFuncCall is an object that describes an invocation of +// method GetUploadByID on an instance of MockDB. +type DBGetUploadByIDFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 int + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 db.Upload + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 bool + // Result2 is the value of the 3rd result returned from this method + // invocation. + Result2 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c DBGetUploadByIDFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c DBGetUploadByIDFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1, c.Result2} +} + +// DBGetUploadsByRepoFunc describes the behavior when the GetUploadsByRepo +// method of the parent MockDB instance is invoked. +type DBGetUploadsByRepoFunc struct { + defaultHook func(context.Context, int, string, string, bool, int, int) ([]db.Upload, int, error) + hooks []func(context.Context, int, string, string, bool, int, int) ([]db.Upload, int, error) + history []DBGetUploadsByRepoFuncCall + mutex sync.Mutex +} + +// GetUploadsByRepo delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockDB) GetUploadsByRepo(v0 context.Context, v1 int, v2 string, v3 string, v4 bool, v5 int, v6 int) ([]db.Upload, int, error) { + r0, r1, r2 := m.GetUploadsByRepoFunc.nextHook()(v0, v1, v2, v3, v4, v5, v6) + m.GetUploadsByRepoFunc.appendCall(DBGetUploadsByRepoFuncCall{v0, v1, v2, v3, v4, v5, v6, r0, r1, r2}) + return r0, r1, r2 +} + +// SetDefaultHook sets function that is called when the GetUploadsByRepo +// method of the parent MockDB instance is invoked and the hook queue is +// empty. +func (f *DBGetUploadsByRepoFunc) SetDefaultHook(hook func(context.Context, int, string, string, bool, int, int) ([]db.Upload, int, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// GetUploadsByRepo method of the parent MockDB instance inovkes the hook at +// the front of the queue and discards it. After the queue is empty, the +// default hook function is invoked for any future action. +func (f *DBGetUploadsByRepoFunc) PushHook(hook func(context.Context, int, string, string, bool, int, int) ([]db.Upload, int, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *DBGetUploadsByRepoFunc) SetDefaultReturn(r0 []db.Upload, r1 int, r2 error) { + f.SetDefaultHook(func(context.Context, int, string, string, bool, int, int) ([]db.Upload, int, error) { + return r0, r1, r2 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *DBGetUploadsByRepoFunc) PushReturn(r0 []db.Upload, r1 int, r2 error) { + f.PushHook(func(context.Context, int, string, string, bool, int, int) ([]db.Upload, int, error) { + return r0, r1, r2 + }) +} + +func (f *DBGetUploadsByRepoFunc) nextHook() func(context.Context, int, string, string, bool, int, int) ([]db.Upload, int, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *DBGetUploadsByRepoFunc) appendCall(r0 DBGetUploadsByRepoFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of DBGetUploadsByRepoFuncCall objects +// describing the invocations of this function. +func (f *DBGetUploadsByRepoFunc) History() []DBGetUploadsByRepoFuncCall { + f.mutex.Lock() + history := make([]DBGetUploadsByRepoFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// DBGetUploadsByRepoFuncCall is an object that describes an invocation of +// method GetUploadsByRepo on an instance of MockDB. +type DBGetUploadsByRepoFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 int + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 string + // Arg3 is the value of the 4th argument passed to this method + // invocation. + Arg3 string + // Arg4 is the value of the 5th argument passed to this method + // invocation. + Arg4 bool + // Arg5 is the value of the 6th argument passed to this method + // invocation. + Arg5 int + // Arg6 is the value of the 7th argument passed to this method + // invocation. + Arg6 int + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 []db.Upload + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 int + // Result2 is the value of the 3rd result returned from this method + // invocation. + Result2 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c DBGetUploadsByRepoFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3, c.Arg4, c.Arg5, c.Arg6} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c DBGetUploadsByRepoFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1, c.Result2} +} + +// DBPackageReferencePagerFunc describes the behavior when the +// PackageReferencePager method of the parent MockDB instance is invoked. +type DBPackageReferencePagerFunc struct { + defaultHook func(context.Context, string, string, string, int, int) (int, db.ReferencePager, error) + hooks []func(context.Context, string, string, string, int, int) (int, db.ReferencePager, error) + history []DBPackageReferencePagerFuncCall + mutex sync.Mutex +} + +// PackageReferencePager delegates to the next hook function in the queue +// and stores the parameter and result values of this invocation. +func (m *MockDB) PackageReferencePager(v0 context.Context, v1 string, v2 string, v3 string, v4 int, v5 int) (int, db.ReferencePager, error) { + r0, r1, r2 := m.PackageReferencePagerFunc.nextHook()(v0, v1, v2, v3, v4, v5) + m.PackageReferencePagerFunc.appendCall(DBPackageReferencePagerFuncCall{v0, v1, v2, v3, v4, v5, r0, r1, r2}) + return r0, r1, r2 +} + +// SetDefaultHook sets function that is called when the +// PackageReferencePager method of the parent MockDB instance is invoked and +// the hook queue is empty. +func (f *DBPackageReferencePagerFunc) SetDefaultHook(hook func(context.Context, string, string, string, int, int) (int, db.ReferencePager, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// PackageReferencePager method of the parent MockDB instance inovkes the +// hook at the front of the queue and discards it. After the queue is empty, +// the default hook function is invoked for any future action. +func (f *DBPackageReferencePagerFunc) PushHook(hook func(context.Context, string, string, string, int, int) (int, db.ReferencePager, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *DBPackageReferencePagerFunc) SetDefaultReturn(r0 int, r1 db.ReferencePager, r2 error) { + f.SetDefaultHook(func(context.Context, string, string, string, int, int) (int, db.ReferencePager, error) { + return r0, r1, r2 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *DBPackageReferencePagerFunc) PushReturn(r0 int, r1 db.ReferencePager, r2 error) { + f.PushHook(func(context.Context, string, string, string, int, int) (int, db.ReferencePager, error) { + return r0, r1, r2 + }) +} + +func (f *DBPackageReferencePagerFunc) nextHook() func(context.Context, string, string, string, int, int) (int, db.ReferencePager, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *DBPackageReferencePagerFunc) appendCall(r0 DBPackageReferencePagerFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of DBPackageReferencePagerFuncCall objects +// describing the invocations of this function. +func (f *DBPackageReferencePagerFunc) History() []DBPackageReferencePagerFuncCall { + f.mutex.Lock() + history := make([]DBPackageReferencePagerFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// DBPackageReferencePagerFuncCall is an object that describes an invocation +// of method PackageReferencePager on an instance of MockDB. +type DBPackageReferencePagerFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 string + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 string + // Arg3 is the value of the 4th argument passed to this method + // invocation. + Arg3 string + // Arg4 is the value of the 5th argument passed to this method + // invocation. + Arg4 int + // Arg5 is the value of the 6th argument passed to this method + // invocation. + Arg5 int + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 int + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 db.ReferencePager + // Result2 is the value of the 3rd result returned from this method + // invocation. + Result2 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c DBPackageReferencePagerFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3, c.Arg4, c.Arg5} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c DBPackageReferencePagerFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1, c.Result2} +} + +// DBResetStalledFunc describes the behavior when the ResetStalled method of +// the parent MockDB instance is invoked. +type DBResetStalledFunc struct { + defaultHook func(context.Context, time.Time) ([]int, error) + hooks []func(context.Context, time.Time) ([]int, error) + history []DBResetStalledFuncCall + mutex sync.Mutex +} + +// ResetStalled delegates to the next hook function in the queue and stores +// the parameter and result values of this invocation. +func (m *MockDB) ResetStalled(v0 context.Context, v1 time.Time) ([]int, error) { + r0, r1 := m.ResetStalledFunc.nextHook()(v0, v1) + m.ResetStalledFunc.appendCall(DBResetStalledFuncCall{v0, v1, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the ResetStalled method +// of the parent MockDB instance is invoked and the hook queue is empty. +func (f *DBResetStalledFunc) SetDefaultHook(hook func(context.Context, time.Time) ([]int, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// ResetStalled method of the parent MockDB instance inovkes the hook at the +// front of the queue and discards it. After the queue is empty, the default +// hook function is invoked for any future action. +func (f *DBResetStalledFunc) PushHook(hook func(context.Context, time.Time) ([]int, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *DBResetStalledFunc) SetDefaultReturn(r0 []int, r1 error) { + f.SetDefaultHook(func(context.Context, time.Time) ([]int, error) { + return r0, r1 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *DBResetStalledFunc) PushReturn(r0 []int, r1 error) { + f.PushHook(func(context.Context, time.Time) ([]int, error) { + return r0, r1 + }) +} + +func (f *DBResetStalledFunc) nextHook() func(context.Context, time.Time) ([]int, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *DBResetStalledFunc) appendCall(r0 DBResetStalledFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of DBResetStalledFuncCall objects describing +// the invocations of this function. +func (f *DBResetStalledFunc) History() []DBResetStalledFuncCall { + f.mutex.Lock() + history := make([]DBResetStalledFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// DBResetStalledFuncCall is an object that describes an invocation of +// method ResetStalled on an instance of MockDB. +type DBResetStalledFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 time.Time + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 []int + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c DBResetStalledFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c DBResetStalledFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + +// DBSameRepoPagerFunc describes the behavior when the SameRepoPager method +// of the parent MockDB instance is invoked. +type DBSameRepoPagerFunc struct { + defaultHook func(context.Context, int, string, string, string, string, int) (int, db.ReferencePager, error) + hooks []func(context.Context, int, string, string, string, string, int) (int, db.ReferencePager, error) + history []DBSameRepoPagerFuncCall + mutex sync.Mutex +} + +// SameRepoPager delegates to the next hook function in the queue and stores +// the parameter and result values of this invocation. +func (m *MockDB) SameRepoPager(v0 context.Context, v1 int, v2 string, v3 string, v4 string, v5 string, v6 int) (int, db.ReferencePager, error) { + r0, r1, r2 := m.SameRepoPagerFunc.nextHook()(v0, v1, v2, v3, v4, v5, v6) + m.SameRepoPagerFunc.appendCall(DBSameRepoPagerFuncCall{v0, v1, v2, v3, v4, v5, v6, r0, r1, r2}) + return r0, r1, r2 +} + +// SetDefaultHook sets function that is called when the SameRepoPager method +// of the parent MockDB instance is invoked and the hook queue is empty. +func (f *DBSameRepoPagerFunc) SetDefaultHook(hook func(context.Context, int, string, string, string, string, int) (int, db.ReferencePager, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// SameRepoPager method of the parent MockDB instance inovkes the hook at +// the front of the queue and discards it. After the queue is empty, the +// default hook function is invoked for any future action. +func (f *DBSameRepoPagerFunc) PushHook(hook func(context.Context, int, string, string, string, string, int) (int, db.ReferencePager, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *DBSameRepoPagerFunc) SetDefaultReturn(r0 int, r1 db.ReferencePager, r2 error) { + f.SetDefaultHook(func(context.Context, int, string, string, string, string, int) (int, db.ReferencePager, error) { + return r0, r1, r2 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *DBSameRepoPagerFunc) PushReturn(r0 int, r1 db.ReferencePager, r2 error) { + f.PushHook(func(context.Context, int, string, string, string, string, int) (int, db.ReferencePager, error) { + return r0, r1, r2 + }) +} + +func (f *DBSameRepoPagerFunc) nextHook() func(context.Context, int, string, string, string, string, int) (int, db.ReferencePager, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *DBSameRepoPagerFunc) appendCall(r0 DBSameRepoPagerFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of DBSameRepoPagerFuncCall objects describing +// the invocations of this function. +func (f *DBSameRepoPagerFunc) History() []DBSameRepoPagerFuncCall { + f.mutex.Lock() + history := make([]DBSameRepoPagerFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// DBSameRepoPagerFuncCall is an object that describes an invocation of +// method SameRepoPager on an instance of MockDB. +type DBSameRepoPagerFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 int + // Arg2 is the value of the 3rd argument passed to this method + // invocation. + Arg2 string + // Arg3 is the value of the 4th argument passed to this method + // invocation. + Arg3 string + // Arg4 is the value of the 5th argument passed to this method + // invocation. + Arg4 string + // Arg5 is the value of the 6th argument passed to this method + // invocation. + Arg5 string + // Arg6 is the value of the 7th argument passed to this method + // invocation. + Arg6 int + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 int + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 db.ReferencePager + // Result2 is the value of the 3rd result returned from this method + // invocation. + Result2 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c DBSameRepoPagerFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1, c.Arg2, c.Arg3, c.Arg4, c.Arg5, c.Arg6} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c DBSameRepoPagerFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1, c.Result2} +} diff --git a/cmd/precise-code-intel-api-server/internal/mocks/mock_reference_pager.go b/cmd/precise-code-intel-api-server/internal/mocks/mock_reference_pager.go new file mode 100644 index 00000000000..363c087b824 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/mocks/mock_reference_pager.go @@ -0,0 +1,262 @@ +// Code generated by github.com/efritz/go-mockgen 0.1.0; DO NOT EDIT. + +package mocks + +import ( + db "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" + "sync" +) + +// MockReferencePager is a mock impelementation of the ReferencePager +// interface (from the package +// github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db) +// used for unit testing. +type MockReferencePager struct { + // CloseTxFunc is an instance of a mock function object controlling the + // behavior of the method CloseTx. + CloseTxFunc *ReferencePagerCloseTxFunc + // PageFromOffsetFunc is an instance of a mock function object + // controlling the behavior of the method PageFromOffset. + PageFromOffsetFunc *ReferencePagerPageFromOffsetFunc +} + +// NewMockReferencePager creates a new mock of the ReferencePager interface. +// All methods return zero values for all results, unless overwritten. +func NewMockReferencePager() *MockReferencePager { + return &MockReferencePager{ + CloseTxFunc: &ReferencePagerCloseTxFunc{ + defaultHook: func(error) error { + return nil + }, + }, + PageFromOffsetFunc: &ReferencePagerPageFromOffsetFunc{ + defaultHook: func(int) ([]db.Reference, error) { + return nil, nil + }, + }, + } +} + +// NewMockReferencePagerFrom creates a new mock of the MockReferencePager +// interface. All methods delegate to the given implementation, unless +// overwritten. +func NewMockReferencePagerFrom(i db.ReferencePager) *MockReferencePager { + return &MockReferencePager{ + CloseTxFunc: &ReferencePagerCloseTxFunc{ + defaultHook: i.CloseTx, + }, + PageFromOffsetFunc: &ReferencePagerPageFromOffsetFunc{ + defaultHook: i.PageFromOffset, + }, + } +} + +// ReferencePagerCloseTxFunc describes the behavior when the CloseTx method +// of the parent MockReferencePager instance is invoked. +type ReferencePagerCloseTxFunc struct { + defaultHook func(error) error + hooks []func(error) error + history []ReferencePagerCloseTxFuncCall + mutex sync.Mutex +} + +// CloseTx delegates to the next hook function in the queue and stores the +// parameter and result values of this invocation. +func (m *MockReferencePager) CloseTx(v0 error) error { + r0 := m.CloseTxFunc.nextHook()(v0) + m.CloseTxFunc.appendCall(ReferencePagerCloseTxFuncCall{v0, r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the CloseTx method of +// the parent MockReferencePager instance is invoked and the hook queue is +// empty. +func (f *ReferencePagerCloseTxFunc) SetDefaultHook(hook func(error) error) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// CloseTx method of the parent MockReferencePager instance inovkes the hook +// at the front of the queue and discards it. After the queue is empty, the +// default hook function is invoked for any future action. +func (f *ReferencePagerCloseTxFunc) PushHook(hook func(error) error) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *ReferencePagerCloseTxFunc) SetDefaultReturn(r0 error) { + f.SetDefaultHook(func(error) error { + return r0 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *ReferencePagerCloseTxFunc) PushReturn(r0 error) { + f.PushHook(func(error) error { + return r0 + }) +} + +func (f *ReferencePagerCloseTxFunc) nextHook() func(error) error { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *ReferencePagerCloseTxFunc) appendCall(r0 ReferencePagerCloseTxFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of ReferencePagerCloseTxFuncCall objects +// describing the invocations of this function. +func (f *ReferencePagerCloseTxFunc) History() []ReferencePagerCloseTxFuncCall { + f.mutex.Lock() + history := make([]ReferencePagerCloseTxFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// ReferencePagerCloseTxFuncCall is an object that describes an invocation +// of method CloseTx on an instance of MockReferencePager. +type ReferencePagerCloseTxFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 error + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c ReferencePagerCloseTxFuncCall) Args() []interface{} { + return []interface{}{c.Arg0} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c ReferencePagerCloseTxFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} + +// ReferencePagerPageFromOffsetFunc describes the behavior when the +// PageFromOffset method of the parent MockReferencePager instance is +// invoked. +type ReferencePagerPageFromOffsetFunc struct { + defaultHook func(int) ([]db.Reference, error) + hooks []func(int) ([]db.Reference, error) + history []ReferencePagerPageFromOffsetFuncCall + mutex sync.Mutex +} + +// PageFromOffset delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockReferencePager) PageFromOffset(v0 int) ([]db.Reference, error) { + r0, r1 := m.PageFromOffsetFunc.nextHook()(v0) + m.PageFromOffsetFunc.appendCall(ReferencePagerPageFromOffsetFuncCall{v0, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the PageFromOffset +// method of the parent MockReferencePager instance is invoked and the hook +// queue is empty. +func (f *ReferencePagerPageFromOffsetFunc) SetDefaultHook(hook func(int) ([]db.Reference, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// PageFromOffset method of the parent MockReferencePager instance inovkes +// the hook at the front of the queue and discards it. After the queue is +// empty, the default hook function is invoked for any future action. +func (f *ReferencePagerPageFromOffsetFunc) PushHook(hook func(int) ([]db.Reference, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultDefaultHook with a function that returns +// the given values. +func (f *ReferencePagerPageFromOffsetFunc) SetDefaultReturn(r0 []db.Reference, r1 error) { + f.SetDefaultHook(func(int) ([]db.Reference, error) { + return r0, r1 + }) +} + +// PushReturn calls PushDefaultHook with a function that returns the given +// values. +func (f *ReferencePagerPageFromOffsetFunc) PushReturn(r0 []db.Reference, r1 error) { + f.PushHook(func(int) ([]db.Reference, error) { + return r0, r1 + }) +} + +func (f *ReferencePagerPageFromOffsetFunc) nextHook() func(int) ([]db.Reference, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *ReferencePagerPageFromOffsetFunc) appendCall(r0 ReferencePagerPageFromOffsetFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of ReferencePagerPageFromOffsetFuncCall +// objects describing the invocations of this function. +func (f *ReferencePagerPageFromOffsetFunc) History() []ReferencePagerPageFromOffsetFuncCall { + f.mutex.Lock() + history := make([]ReferencePagerPageFromOffsetFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// ReferencePagerPageFromOffsetFuncCall is an object that describes an +// invocation of method PageFromOffset on an instance of MockReferencePager. +type ReferencePagerPageFromOffsetFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 int + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 []db.Reference + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c ReferencePagerPageFromOffsetFuncCall) Args() []interface{} { + return []interface{}{c.Arg0} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c ReferencePagerPageFromOffsetFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} diff --git a/cmd/precise-code-intel-api-server/internal/server/gitserver.go b/cmd/precise-code-intel-api-server/internal/server/gitserver.go new file mode 100644 index 00000000000..2d54ec48e03 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/server/gitserver.go @@ -0,0 +1,25 @@ +package server + +import ( + "bytes" + "context" + + "github.com/sourcegraph/sourcegraph/cmd/frontend/db" + "github.com/sourcegraph/sourcegraph/internal/api" + "github.com/sourcegraph/sourcegraph/internal/gitserver" +) + +func getTipCommit(repositoryID int) (string, error) { + repo, err := db.Repos.Get(context.Background(), api.RepoID(repositoryID)) + if err != nil { + return "", err + } + + cmd := gitserver.DefaultClient.Command("git", "rev-parse", "HEAD") + cmd.Repo = gitserver.Repo{Name: repo.Name} + out, err := cmd.CombinedOutput(context.Background()) + if err != nil { + return "", err + } + return string(bytes.TrimSpace(out)), nil +} diff --git a/cmd/precise-code-intel-api-server/internal/server/handler.go b/cmd/precise-code-intel-api-server/internal/server/handler.go new file mode 100644 index 00000000000..d4a0c84d02a --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/server/handler.go @@ -0,0 +1,311 @@ +package server + +import ( + "encoding/json" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + + "github.com/gorilla/mux" + "github.com/inconshreveable/log15" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/api" +) + +const DefaultUploadPageSize = 50 + +func (s *Server) handler() http.Handler { + mux := mux.NewRouter() + mux.Path("/uploads/{id:[0-9]+}").Methods("GET").HandlerFunc(s.handleGetUploadByID) + mux.Path("/uploads/{id:[0-9]+}").Methods("DELETE").HandlerFunc(s.handleDeleteUploadByID) + mux.Path("/uploads/repository/{id:[0-9]+}").Methods("GET").HandlerFunc(s.handleGetUploadsByRepo) + mux.Path("/upload").Methods("POST").HandlerFunc(s.handleEnqueue) + mux.Path("/exists").Methods("GET").HandlerFunc(s.handleExists) + mux.Path("/definitions").Methods("GET").HandlerFunc(s.handleDefinitions) + mux.Path("/references").Methods("GET").HandlerFunc(s.handleReferences) + mux.Path("/hover").Methods("GET").HandlerFunc(s.handleHover) + mux.Path("/uploads").Methods("POST").HandlerFunc(s.handleUploads) + mux.Path("/prune").Methods("POST").HandlerFunc(s.handlePrune) + mux.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + }) + return mux +} + +// GET /uploads/{id:[0-9]+} +func (s *Server) handleGetUploadByID(w http.ResponseWriter, r *http.Request) { + upload, exists, err := s.db.GetUploadByID(r.Context(), int(idFromRequest(r))) + if err != nil { + log15.Error("Failed to retrieve upload", "error", err) + http.Error(w, fmt.Sprintf("failed to retrieve upload: %s", err.Error()), http.StatusInternalServerError) + return + } + if !exists { + http.Error(w, "upload not found", http.StatusNotFound) + return + } + + writeJSON(w, upload) +} + +// DELETE /uploads/{id:[0-9]+} +func (s *Server) handleDeleteUploadByID(w http.ResponseWriter, r *http.Request) { + exists, err := s.db.DeleteUploadByID(r.Context(), int(idFromRequest(r)), getTipCommit) + if err != nil { + log15.Error("Failed to delete upload", "error", err) + http.Error(w, fmt.Sprintf("failed to delete upload: %s", err.Error()), http.StatusInternalServerError) + return + } + if !exists { + http.Error(w, "upload not found", http.StatusNotFound) + return + } + + w.WriteHeader(http.StatusNoContent) +} + +// GET /uploads/repository/{id:[0-9]+} +func (s *Server) handleGetUploadsByRepo(w http.ResponseWriter, r *http.Request) { + id := int(idFromRequest(r)) + limit := getQueryIntDefault(r, "limit", DefaultUploadPageSize) + offset := getQueryInt(r, "offset") + + uploads, totalCount, err := s.db.GetUploadsByRepo( + r.Context(), + id, + getQuery(r, "state"), + getQuery(r, "query"), + getQueryBool(r, "visibleAtTip"), + limit, + offset, + ) + if err != nil { + log15.Error("Failed to list uploads", "error", err) + http.Error(w, fmt.Sprintf("failed to list uploads: %s", err.Error()), http.StatusInternalServerError) + return + } + + if offset+len(uploads) < totalCount { + w.Header().Set("Link", makeNextLink(r.URL, map[string]interface{}{ + "limit": limit, + "offset": offset + len(uploads), + })) + } + + writeJSON(w, map[string]interface{}{"uploads": uploads, "totalCount": totalCount}) +} + +// POST /upload +func (s *Server) handleEnqueue(w http.ResponseWriter, r *http.Request) { + f, err := ioutil.TempFile("", "upload-") + if err != nil { + log15.Error("Failed to open target file", "error", err) + http.Error(w, fmt.Sprintf("failed to open target file: %s", err.Error()), http.StatusInternalServerError) + return + } + defer os.Remove(f.Name()) + defer f.Close() + + if _, err := io.Copy(f, r.Body); err != nil { + log15.Error("Failed to write payload", "error", err) + http.Error(w, fmt.Sprintf("failed to write payload: %s", err.Error()), http.StatusInternalServerError) + return + } + + indexerName := getQuery(r, "indexerName") + if indexerName == "" { + if indexerName, err = readIndexerNameFromFile(f); err != nil { + log15.Error("Failed to read indexer name from upload", "error", err) + http.Error(w, fmt.Sprintf("failed to read indexer name from upload: %s", err.Error()), http.StatusInternalServerError) + return + } + } + + id, closer, err := s.db.Enqueue( + r.Context(), + getQuery(r, "commit"), + sanitizeRoot(getQuery(r, "root")), + "{}", // TODO(efritz) - write tracing code + getQueryInt(r, "repositoryId"), + indexerName, + ) + if err == nil { + err = closer.CloseTx(s.bundleManagerClient.SendUpload(r.Context(), id, f)) + } + if err != nil { + log15.Error("Failed to enqueue payload", "error", err) + http.Error(w, fmt.Sprintf("failed to enqueue payload: %s", err.Error()), http.StatusInternalServerError) + return + } + + w.WriteHeader(http.StatusAccepted) + writeJSON(w, map[string]interface{}{"id": id}) +} + +// GET /exists +func (s *Server) handleExists(w http.ResponseWriter, r *http.Request) { + dumps, err := s.api.FindClosestDumps( + r.Context(), + getQueryInt(r, "repositoryId"), + getQuery(r, "commit"), + getQuery(r, "path"), + ) + if err != nil { + log15.Error("Failed to handle exists request", "error", err) + http.Error(w, fmt.Sprintf("failed to handle exists request: %s", err.Error()), http.StatusInternalServerError) + return + } + + writeJSON(w, map[string]interface{}{"uploads": dumps}) +} + +// GET /definitions +func (s *Server) handleDefinitions(w http.ResponseWriter, r *http.Request) { + defs, err := s.api.Definitions( + r.Context(), + getQuery(r, "path"), + getQueryInt(r, "line"), + getQueryInt(r, "character"), + getQueryInt(r, "uploadId"), + ) + if err != nil { + if err == api.ErrMissingDump { + http.Error(w, "no such dump", http.StatusNotFound) + return + } + + log15.Error("Failed to handle definitions request", "error", err) + http.Error(w, fmt.Sprintf("failed to handle definitions request: %s", err.Error()), http.StatusInternalServerError) + return + } + + outers, err := serializeLocations(defs) + if err != nil { + log15.Error("Failed to resolve locations", "error", err) + http.Error(w, fmt.Sprintf("failed to resolve locations: %s", err.Error()), http.StatusInternalServerError) + return + } + + writeJSON(w, map[string]interface{}{"locations": outers}) +} + +// GET /references +func (s *Server) handleReferences(w http.ResponseWriter, r *http.Request) { + cursor, err := api.DecodeOrCreateCursor( + getQuery(r, "path"), + getQueryInt(r, "line"), + getQueryInt(r, "character"), + getQueryInt(r, "uploadId"), + getQuery(r, "rawCursor"), + s.db, + s.bundleManagerClient, + ) + if err != nil { + if err == api.ErrMissingDump { + http.Error(w, "no such dump", http.StatusNotFound) + return + } + + log15.Error("Failed to prepare cursor", "error", err) + http.Error(w, fmt.Sprintf("failed to prepare cursor: %s", err.Error()), http.StatusInternalServerError) + return + } + + locations, newCursor, hasNewCursor, err := s.api.References( + r.Context(), + getQueryInt(r, "repositoryId"), + getQuery(r, "commit"), + getQueryInt(r, "limit"), + cursor, + ) + if err != nil { + log15.Error("Failed to handle references request", "error", err) + http.Error(w, fmt.Sprintf("failed to handle references request: %s", err.Error()), http.StatusInternalServerError) + return + } + + outers, err := serializeLocations(locations) + if err != nil { + log15.Error("Failed to resolve locations", "error", err) + http.Error(w, fmt.Sprintf("failed to resolve locations: %s", err.Error()), http.StatusInternalServerError) + return + } + + if hasNewCursor { + w.Header().Set("Link", makeNextLink(r.URL, map[string]interface{}{ + "cursor": api.EncodeCursor(newCursor), + })) + } + + writeJSON(w, map[string]interface{}{"locations": outers}) +} + +// GET /hover +func (s *Server) handleHover(w http.ResponseWriter, r *http.Request) { + text, rn, exists, err := s.api.Hover( + r.Context(), + getQuery(r, "path"), + getQueryInt(r, "line"), + getQueryInt(r, "character"), + getQueryInt(r, "uploadId"), + ) + if err != nil { + if err == api.ErrMissingDump { + http.Error(w, "no such dump", http.StatusNotFound) + return + } + + log15.Error("Failed to handle hover request", "error", err) + http.Error(w, fmt.Sprintf("failed to handle hover request: %s", err.Error()), http.StatusInternalServerError) + return + } + + if !exists { + writeJSON(w, nil) + } else { + writeJSON(w, map[string]interface{}{"text": text, "range": rn}) + } +} + +// POST /uploads +func (s *Server) handleUploads(w http.ResponseWriter, r *http.Request) { + payload := struct { + IDs []int `json:"ids"` + }{} + if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { + log15.Error("Failed to read request body", "error", err) + http.Error(w, fmt.Sprintf("failed to read request body: %s", err.Error()), http.StatusInternalServerError) + return + } + + states, err := s.db.GetStates(r.Context(), payload.IDs) + if err != nil { + log15.Error("Failed to retrieve upload states", "error", err) + http.Error(w, fmt.Sprintf("failed to retrieve upload states: %s", err.Error()), http.StatusInternalServerError) + return + } + + pairs := []interface{}{} + for k, v := range states { + pairs = append(pairs, []interface{}{k, v}) + } + + writeJSON(w, map[string]interface{}{"type": "map", "value": pairs}) +} + +// POST /prune +func (s *Server) handlePrune(w http.ResponseWriter, r *http.Request) { + id, prunable, err := s.db.DeleteOldestDump(r.Context()) + if err != nil { + log15.Error("Failed to prune upload", "error", err) + http.Error(w, fmt.Sprintf("failed to prune upload: %s", err.Error()), http.StatusInternalServerError) + return + } + + if !prunable { + writeJSON(w, nil) + } else { + writeJSON(w, map[string]interface{}{"id": id}) + } +} diff --git a/cmd/precise-code-intel-api-server/internal/server/indexer_name.go b/cmd/precise-code-intel-api-server/internal/server/indexer_name.go new file mode 100644 index 00000000000..57efd9c1773 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/server/indexer_name.go @@ -0,0 +1,69 @@ +package server + +import ( + "bufio" + "compress/gzip" + "encoding/json" + "errors" + "io" + "os" +) + +type metaDataVertex struct { + Label string `json:"label"` + ToolInfo toolInfo `json:"toolInfo"` +} + +type toolInfo struct { + Name string `json:"name"` +} + +var ErrInvalidMetaDataVertex = errors.New("invalid metadata vertex") + +// readIndexerNameFromFile returns the name of the tool that generated +// the given index file. This function reads only the first line of the +// file, where the metadata vertex is assumed to be in all valid dumps. +// This function also resets the offset of the file to the beginning of +// the file before and after reading. +func readIndexerNameFromFile(f *os.File) (string, error) { + _, err1 := f.Seek(0, 0) + name, err2 := readIndexerName(f) + _, err3 := f.Seek(0, 0) + + for _, err := range []error{err1, err2, err3} { + if err != nil { + return "", err + } + } + + return name, nil +} + +// readIndexerName returns the name of the tool that generated the given +// index contents. This function reads only the first line of the file, +// where the metadata vertex is assumed to be in all valid dumps. +func readIndexerName(r io.Reader) (string, error) { + gzipReader, err := gzip.NewReader(r) + if err != nil { + return "", err + } + + line, isPrefix, err := bufio.NewReader(gzipReader).ReadLine() + if err != nil { + return "", err + } + if isPrefix { + return "", errors.New("metaData vertex exceeds buffer") + } + + meta := metaDataVertex{} + if err := json.Unmarshal(line, &meta); err != nil { + return "", ErrInvalidMetaDataVertex + } + + if meta.Label != "metaData" || meta.ToolInfo.Name == "" { + return "", ErrInvalidMetaDataVertex + } + + return meta.ToolInfo.Name, nil +} diff --git a/cmd/precise-code-intel-api-server/internal/server/indexer_name_test.go b/cmd/precise-code-intel-api-server/internal/server/indexer_name_test.go new file mode 100644 index 00000000000..7488294b4a3 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/server/indexer_name_test.go @@ -0,0 +1,90 @@ +package server + +import ( + "bufio" + "bytes" + "compress/gzip" + "io" + "io/ioutil" + "os" + "strings" + "testing" +) + +const testMetaDataVertex = `{"label": "metaData", "toolInfo": {"name": "test"}}` +const testVertex = `{"id": "a", "type": "edge", "label": "textDocument/references", "outV": "b", "inV": "c"}` + +func TestReadIndexerName(t *testing.T) { + name, err := readIndexerName(generateTestIndex(testMetaDataVertex)) + if err != nil { + t.Fatalf("unexpected error reading indexer name: %s", err) + } + if name != "test" { + t.Errorf("unexpected indexer name. want=%s have=%s", "test", name) + } +} + +func TestReadIndexerNameMalformed(t *testing.T) { + for _, metaDataVertex := range []string{`invalid json`, `{"label": "textDocument/references"}`} { + if _, err := readIndexerName(generateTestIndex(metaDataVertex)); err != ErrInvalidMetaDataVertex { + t.Fatalf("unexpected error reading indexer name. want=%q have=%q", ErrInvalidMetaDataVertex, err) + } + } +} + +func TestReadIndexerNameFromFile(t *testing.T) { + tempFile, err := ioutil.TempFile("", "") + if err != nil { + t.Fatalf("unexpected error creating temp file: %s", err) + } + defer os.Remove(tempFile.Name()) + + _, _ = io.Copy(tempFile, generateTestIndex(testMetaDataVertex)) + + name, err := readIndexerNameFromFile(tempFile) + if err != nil { + t.Fatalf("unexpected error reading indexer name: %s", err) + } + if name != "test" { + t.Errorf("unexpected indexer name. want=%s have=%s", "test", name) + } + + // Ensure reader is reset to beginning + firstLine, err := testReadFirstLine(tempFile) + if err != nil { + t.Fatalf("unexpected error reading from file %s", err) + } + if firstLine != testMetaDataVertex { + t.Errorf("unexpected buffer location. want=%q have=%q", testMetaDataVertex, firstLine) + } +} + +func generateTestIndex(metaDataVertex string) io.Reader { + lines := []string{metaDataVertex} + for i := 0; i < 20000; i++ { + lines = append(lines, testVertex) + } + + content := strings.Join(lines, "\n") + "\n" + + var buf bytes.Buffer + w := gzip.NewWriter(&buf) + _, _ = io.Copy(w, bytes.NewReader([]byte(content))) + w.Close() + + return bytes.NewReader(buf.Bytes()) +} + +func testReadFirstLine(r io.Reader) (string, error) { + gzipReader, err := gzip.NewReader(r) + if err != nil { + return "", err + } + + line, _, err := bufio.NewReader(gzipReader).ReadLine() + if err != nil { + return "", err + } + + return string(line), nil +} diff --git a/cmd/precise-code-intel-api-server/internal/server/locations.go b/cmd/precise-code-intel-api-server/internal/server/locations.go new file mode 100644 index 00000000000..6c600a425cd --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/server/locations.go @@ -0,0 +1,27 @@ +package server + +import ( + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/api" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" +) + +type APILocation struct { + RepositoryID int `json:"repositoryId"` + Commit string `json:"commit"` + Path string `json:"path"` + Range bundles.Range `json:"range"` +} + +func serializeLocations(resolvedLocations []api.ResolvedLocation) ([]APILocation, error) { + var apiLocations []APILocation + for _, res := range resolvedLocations { + apiLocations = append(apiLocations, APILocation{ + RepositoryID: res.Dump.RepositoryID, + Commit: res.Dump.Commit, + Path: res.Path, + Range: res.Range, + }) + } + + return apiLocations, nil +} diff --git a/cmd/precise-code-intel-api-server/internal/server/server.go b/cmd/precise-code-intel-api-server/internal/server/server.go new file mode 100644 index 00000000000..29734d6d09e --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/server/server.go @@ -0,0 +1,50 @@ +package server + +import ( + "net" + "net/http" + "os" + "strconv" + + "github.com/inconshreveable/log15" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/api" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" + "github.com/sourcegraph/sourcegraph/internal/trace/ot" +) + +type Server struct { + host string + port int + db db.DB + bundleManagerClient bundles.BundleManagerClient + api api.CodeIntelAPI +} + +type ServerOpts struct { + Host string + Port int + DB db.DB + BundleManagerClient bundles.BundleManagerClient +} + +func New(opts ServerOpts) *Server { + return &Server{ + host: opts.Host, + port: opts.Port, + db: opts.DB, + bundleManagerClient: opts.BundleManagerClient, + api: api.New(opts.DB, opts.BundleManagerClient), + } +} + +func (s *Server) Start() { + addr := net.JoinHostPort(s.host, strconv.FormatInt(int64(s.port), 10)) + handler := ot.Middleware(s.handler()) + server := &http.Server{Addr: addr, Handler: handler} + + if err := server.ListenAndServe(); err != http.ErrServerClosed { + log15.Error("Failed to start server", "error", err) + os.Exit(1) + } +} diff --git a/cmd/precise-code-intel-api-server/internal/server/util.go b/cmd/precise-code-intel-api-server/internal/server/util.go new file mode 100644 index 00000000000..9718eb11c54 --- /dev/null +++ b/cmd/precise-code-intel-api-server/internal/server/util.go @@ -0,0 +1,90 @@ +package server + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strconv" + "strings" + + "github.com/gorilla/mux" + "github.com/inconshreveable/log15" + "github.com/tomnomnom/linkheader" +) + +func getQuery(r *http.Request, name string) string { + return r.URL.Query().Get(name) +} + +func getQueryInt(r *http.Request, name string) int { + value, _ := strconv.Atoi(r.URL.Query().Get(name)) + return value +} + +func getQueryIntDefault(r *http.Request, name string, defaultValue int) int { + value, err := strconv.Atoi(r.URL.Query().Get(name)) + if err != nil { + value = defaultValue + } + return value +} + +func getQueryBool(r *http.Request, name string) bool { + value, _ := strconv.ParseBool(r.URL.Query().Get(name)) + return value +} + +func makeNextLink(url *url.URL, newQueryValues map[string]interface{}) string { + q := url.Query() + for k, v := range newQueryValues { + q.Set(k, fmt.Sprintf("%v", v)) + } + url.RawQuery = q.Encode() + + header := linkheader.Link{ + URL: url.String(), + Rel: "next", + } + return header.String() +} + +// idFromRequest returns the database id from the request URL's path. This method +// must only be called from routes containing the `id:[0-9]+` pattern, as the error +// return from ParseInt is not checked. +func idFromRequest(r *http.Request) int64 { + id, _ := strconv.ParseInt(mux.Vars(r)["id"], 10, 64) + return id +} + +// copyAll writes the contents of r to w and logs on write failure. +func copyAll(w http.ResponseWriter, r io.Reader) { + if _, err := io.Copy(w, r); err != nil { + log15.Error("Failed to write payload to client", "error", err) + } +} + +// writeJSON writes the JSON-encoded payload to w and logs on write failure. +// If there is an encoding error, then a 500-level status is written to w. +func writeJSON(w http.ResponseWriter, payload interface{}) { + data, err := json.Marshal(payload) + if err != nil { + log15.Error("Failed to serialize result", "error", err) + http.Error(w, fmt.Sprintf("failed to serialize result: %s", err.Error()), http.StatusInternalServerError) + return + } + + copyAll(w, bytes.NewReader(data)) +} + +func sanitizeRoot(s string) string { + if s == "" || s == "/" { + return "" + } + if !strings.HasSuffix(s, "/") { + s += "/" + } + return s +} diff --git a/cmd/precise-code-intel-api-server/main.go b/cmd/precise-code-intel-api-server/main.go new file mode 100644 index 00000000000..f84bc9325a6 --- /dev/null +++ b/cmd/precise-code-intel-api-server/main.go @@ -0,0 +1,79 @@ +package main + +import ( + "log" + "os" + "os/signal" + "syscall" + + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/bundles" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/db" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/janitor" + "github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server/internal/server" + "github.com/sourcegraph/sourcegraph/internal/conf" + "github.com/sourcegraph/sourcegraph/internal/debugserver" + "github.com/sourcegraph/sourcegraph/internal/env" + "github.com/sourcegraph/sourcegraph/internal/tracer" +) + +func main() { + env.Lock() + env.HandleHelpFlag() + tracer.Init() + + var ( + janitorInterval = mustParseInterval(rawJanitorInterval, "PRECISE_CODE_INTEL_JANITOR_INTERVAL") + bundleManagerURL = mustGet(rawBundleManagerURL, "PRECISE_CODE_INTEL_BUNDLE_MANAGER_URL") + ) + + db := mustInitializeDatabase() + + host := "" + if env.InsecureDev { + host = "127.0.0.1" + } + + serverInst := server.New(server.ServerOpts{ + Host: host, + Port: 3186, + DB: db, + BundleManagerClient: bundles.New(bundleManagerURL), + }) + + janitorInst := janitor.NewJanitor(janitor.JanitorOpts{ + DB: db, + JanitorInterval: janitorInterval, + }) + + go serverInst.Start() + go janitorInst.Start() + go debugserver.Start() + waitForSignal() +} + +func mustInitializeDatabase() db.DB { + postgresDSN := conf.Get().ServiceConnections.PostgresDSN + conf.Watch(func() { + if newDSN := conf.Get().ServiceConnections.PostgresDSN; postgresDSN != newDSN { + log.Fatalf("Detected repository DSN change, restarting to take effect: %s", newDSN) + } + }) + + db, err := db.New(postgresDSN) + if err != nil { + log.Fatalf("failed to initialize db store: %s", err) + } + + return db +} + +func waitForSignal() { + signals := make(chan os.Signal, 2) + signal.Notify(signals, syscall.SIGINT, syscall.SIGHUP) + + for i := 0; i < 2; i++ { + <-signals + } + + os.Exit(0) +} diff --git a/cmd/precise-code-intel-api-server/testdata/filters/normal/1 b/cmd/precise-code-intel-api-server/testdata/filters/normal/1 new file mode 100644 index 00000000000..92f3828bbeb --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/normal/1 @@ -0,0 +1 @@ +1f8b0800000000000013d5974d4ec3301085ef9275903c7f9e310740dca1620115120811166d5615776f365569e5b66e12c746df2a1b67e679dee465d774fdf7f3ebe6e3a9efd6dbcf9f6ed33c826f9bb77efdf5be1d1e56ae9d1386c0e4b83532f3ce663dfb2fe88282e0e473c655089e8c33f6c6c7b208d5e793f16629c5de7c0a1023a862aa1227125e824884994af518b7081038ad45f63ab8a6c6b0cb4a9777e00181958d7cc2e81d485993e88d495872749ae493a588af3a48367dbd9cf720e44d5d805c3e1764b432b2790537cc74cad731cd3006a1c675887ea87e5a06f8ff731d679c63179c5921a520e8961445b299fd9cb9a2717e2607308c7c14ef8d8a995bbc18df535d02c57b98973131e9481db71a237ed31505ac1cc6b8e7acfc3f5a2fbf7be990244eef100000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/normal/10 b/cmd/precise-code-intel-api-server/testdata/filters/normal/10 new file mode 100644 index 00000000000..6580adcbd00 --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/normal/10 @@ -0,0 +1 @@ +1f8b0800000000000013ed97410ac2301045efd27585643233193d80780771a14550c4ba68bb2adeddec14a1306ab053286f95f2493e3ff969db177577ddec9bd3baababf67cab9b62e5b92c0e5d7539b669b075655e2488b093ccb3667538ba83210244b6ebce1ae0d06e58f66b30a363011e234a60c3a7cd781966b4102088dd8d9c4617bec7738c11d20792429a0a4751a364a2a0d1a15b6a64402a7b2ad1d073786e2fb06020542e3a627c04e99d8b0ae11f027c59ec83f866def101c1a72365f9b6f1a6ddd9c26e52b67fbda6d0839fd8dd1f632fe760aa100000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/normal/11 b/cmd/precise-code-intel-api-server/testdata/filters/normal/11 new file mode 100644 index 00000000000..2bd3c6d582f --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/normal/11 @@ -0,0 +1 @@ +1f8b0800000000000013ed974d6ac3301085efe2750a9aff510f507287d2451b0a09a5ee22f12ae4ee1581800d216952c9964bf95602db7a7abcd18cf74ddb7d2e5fb7eba7ae5ded365fedb679045d346fddeae37d9716cf613117304403c151f6e251cfc57ef5213508ee3aa6ae1f6957042e270a8811ccf0ba3f67df0e589b5fc3c341b071e23c176a70235d8ff93ee6948a36dc17df3ea8ce242c39b5e500d2dd25f61b557067715f86439cd22a21750b116ac8733d38c439187263932d11df3ea94990317875bd8c2132854baa0419bdb43fe700252f6b97fcd7760f221166fa7b96109a4e11e02130b982130f69dc3776d2e32f0ba8a5e13cebc0940395d47f27573104ab1bdd6ea17c65bf1cbe0125fb0eb6ab100000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/normal/12 b/cmd/precise-code-intel-api-server/testdata/filters/normal/12 new file mode 100644 index 00000000000..d57fcc8b636 --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/normal/12 @@ -0,0 +1 @@ +1f8b0800000000000013ed97cd6ac3300c80df25e716ac1f4bea1ea0ec1dc60e5b186c94658736a7b2779f7b2a29f5d2ac4ee541f94e0127fe2c5996b36fbafef3f165fbbeeebb76f7f1d56d9b079045f3dab79bb75d7a780a8bb2189949b0c25f2d6a78c11876312354c9d989424891f511cb8382c0fe521878183808e86f75a4feaab873209d8d63439669c32b1b09df329d28c614398efb9dbc775a18e5813445d4a96273c361559b520922325abde7884f71cc41659d16829232985b5703cc659461c514fcc375a63440c8fcc5ee4c07881154b39bae06f22531cb6ceeeb1dd888a6ec5c705d1a3277c02446fa7bdbffedffeb3a70f2c5ed1cffa128aee2f9fb070af8abf9b1100000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/normal/2 b/cmd/precise-code-intel-api-server/testdata/filters/normal/2 new file mode 100644 index 00000000000..ff641ef997c --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/normal/2 @@ -0,0 +1 @@ +1f8b0800000000000013dd97cf0e82300cc6df853326eb9f75c50730be83f1a0c44463c4037032bebb249e5043200c36ccefb4cbdaef4bbbae8fa4a86fdb4379ded4455e5dee4599ac41d2e458e7d753d51c7626f50943c664d8eb9d6dd0640e2c4e18a10b10d2e9d4a1610d24ac9546f00cde00318273e8cf13226b99291e81605c2cc9c441971bcdc3153abde128a98ae92e611465b26c97a8af3f844ebe7d008fed1d8a4f0d96449dc9e0bf5a5b1c98a696c78e3f852c465f5010789cb6e517b23f2c32ea3c8684e8363b5bb4b0ffdd218cfe5c61b403f0f7e8ea0f0457e09755f3563a569228f69529896425f3cd104dd3af4bfbe70b54fbb4fda8100000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/normal/3 b/cmd/precise-code-intel-api-server/testdata/filters/normal/3 new file mode 100644 index 00000000000..a313b3658fc --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/normal/3 @@ -0,0 +1 @@ +1f8b0800000000000013d557cb6ac3400cfc179f53583d56d2e6034aff21e49086424b8973487c0afdf7f8103001a7f143b637ccc118e3d57876465e5d8ab23a7cec4edfef55b93fff1ccb53b10659159fd5fef7eb5cdf6cc2ca17466612cc79d506189242c4f13c6f57084aca60c89351eefb81dca847a8329d96c3b00c27204650c5ae95ef649c0b5d2bb68704a836e37867e786f11de135347943606523e9613ca31424caec5c17494777404bcc518c29f20262792292988604be969658afdbd44046cb777bbbe5c420796a0479d826875d01d1fa3ffa40108fe3555b7a9f6346d70e2e1507e776f89bf9627c2f238a91995c83def39c382d40c8f8c1a34c28ce8d67edffff392c5fcda6198b181253f09a4d970e876fd243fbccbefdbb027ceba5bff6100000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/normal/4 b/cmd/precise-code-intel-api-server/testdata/filters/normal/4 new file mode 100644 index 00000000000..f40beb8262b --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/normal/4 @@ -0,0 +1 @@ +1f8b0800000000000013dd974d4ec3400c85ef927591c67f63870320ee8058940a0984088b362bc4dd995d5229a33aed0426d1b74a6465ec273f8ff3dd74fde7e3fef8f6d07787d3fb57776cee21ee9a97fef0f17a4a0f4f61571623b318acf0570730b40a82b7e7b95886d7d6c5434a841a6b4bf0ef01620455f42a7126616d4cfb020882dedecc5b621d6adc21b0b2519cd1724b8fc61c55fb2279c06df0b520144d430b4bb5b220a3d52b9acf1b06ed3aac3e05444d1753daa432b58d4393fb44739163a2a4c671c471683d61289ea86c0d6741b9f723eb62342661e7a123f91cdd5c5e43c1348dd91158504501ba7cdc0c15b701910833959c057317c7850bcc2ef3dbbbf97c5cb33c0dd4ab59ddbf6dffed8aa2169fe4f9e7173e984c74f0100000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/normal/5 b/cmd/precise-code-intel-api-server/testdata/filters/normal/5 new file mode 100644 index 00000000000..6983eb4f99a --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/normal/5 @@ -0,0 +1 @@ +1f8b0800000000000013dd973d0ec2300c85efd2b948f14f6c870320ee80180021811065804e88bbd3858d4aa88d885bbd2943ace72f76123faba6bdae77f7d3aa6d0e8ff3adb9574b90badab787cbf1d12d36a19e8a30248588d9e241505206432e9eda2741b6e226fa44a8f27f77408ca08a7eb90c7506d4d55fbe62f622233309638e6b6e4c8c529028c57d78127c696814638a3c715291c43424c85bc512bbb8c5731b278394130af8e0e1e16102d1ee89ec0192fbd7f4ab22329a073a3df60677e8f09d7e35fed6228a9199e68706848c4b9bf0a405022b1b49cfb0e2659a2a2f86c414a6ce236b4f43f83e6d6f5f6f54320597aa100000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/normal/6 b/cmd/precise-code-intel-api-server/testdata/filters/normal/6 new file mode 100644 index 00000000000..ebadbb98e9b --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/normal/6 @@ -0,0 +1 @@ +1f8b0800000000000013dd57cb4ec33010fc979c8be47d7877cd0720fe0171800a0984088736a78a7fc74242552aa7711abb09684e91fc981defec6e0e4ddb7ddc3fed5eefba76bb7ffb6c77cd2dc8a679eeb6ef2ffbf8f1e03665616426ce0a9f7a04baa0e0713ecf8c355c2d8a545c7ca444a8324450145c94f89adcb2f80b02d72305c408aa989b583d397f0e70b826c9d2360102a7f373fb3f610d6ac48a39b6e42666bfb291707ee92b552a518cc9b31f6779b2efd423e501f10aaf5389f54ec8b6fc14b00b7348cd85273175016a25b74746abfdb69723cf2c06610de61fc3c44e5cdf714aca608b75bb61c3320426778ed715f336711508595dd57c35c7ff451079cf4c2525993a26560e70708cafd3d50655595c895ff42b3f88c6b7ca98aefaa82d9df8d89f2fde7deedf6d1e70f28497c2d21629eaf7241ebfbe01fcefbb05f7100000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/normal/7 b/cmd/precise-code-intel-api-server/testdata/filters/normal/7 new file mode 100644 index 00000000000..a0e59e6d528 --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/normal/7 @@ -0,0 +1 @@ +1f8b0800000000000013d5964d0ac2301085efd27585cc4f26a90710ef202eb4088a5817b52bf1ee16c15dc158924ccab7eaa67d6f3a6f669e5537dcb687febc19baf671b9777db506a9abe3d05e4f8ff16167ea9830344c866b4fde8bf151df1d9779da40c8730675844ef4aa876a5f9ea9d7f0ef621159cb4c5adeca4f44d98c534b5bc29715023bf624015d17068a67b26c53780c0a472e74e75a3a00f3b8b2c8e8750a280ecc38c242b65ffc80e40265949e63c12f8f5c2d3e074b8e1a8b465b470ad0340eecd24eb23f3d4e6c3e204670aee0ae0bcf04a82bd5a7dcff387d94147437a5884229de3eec5f6fb32efbf9a9100000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/normal/8 b/cmd/precise-code-intel-api-server/testdata/filters/normal/8 new file mode 100644 index 00000000000..23782c1c536 --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/normal/8 @@ -0,0 +1 @@ +1f8b0800000000000013ed974d0ac2400c85efd2b5c2e46f927a00f10ee2428ba08875a15d897777967531b652451be45b0d3c48f2482633d7a26e8e8bf579376feaeab23fd5e7620671526c9aeab0bda4c3324cc602865241f0eb79bcbf2eb6af27f13b0031822afaf3040882faebdf217873c3c82c067fad3b047037ca42d13494e0ad7b8761508ed710889a764e7a1a656a6b4bd3be16cd29db44499dd243c7a1ec2343e9a3cad6f020ea0e168d49b867c89679828cf67ce23d382840dde15ef0d0074422cc34de7b205b186af4b6c68630456065a3f8ffbb38e7f3c3bcbadd01cd909fc0a7100000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/normal/9 b/cmd/precise-code-intel-api-server/testdata/filters/normal/9 new file mode 100644 index 00000000000..664ba92c9e3 --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/normal/9 @@ -0,0 +1 @@ +1f8b0800000000000013ed57cb0ac23010fc979e15b28f64b77e80f80fe2414550c47a687b12ffdd1e9482545113eda23287904b76329909cc212beadd645eaec775b1ac36fba2cc461006d9a25e6e5755b399ba415a28a906a7894f4dcaf0bc8213120645ee9dd23508255893d022a716e8f8f3e41e9d683f1369f02bf71c22b0b05278c273bd18b497a15184833279f6a177267610bca7560f8f8c6af7515f89461ce0ef950b208808de10045d2ee0316e00da75decbc1f01027ca37a1f969545c6e44112046681c6dc374404d63e816c6722e3e8ffb7dcaae52ef69380c39934bd5316d4522f22eaebb7acf8e270cc7c14ab7100000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/stress/128kb-08 b/cmd/precise-code-intel-api-server/testdata/filters/stress/128kb-08 new file mode 100644 index 00000000000..1ccb0aaeaff --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/stress/128kb-08 @@ -0,0 +1 @@ +1f8b08000000000000138d5ac9ae1d3510fd97ac6f24cfede60310ff80584084044284459215e2dff158b3fb465ebc77bbdb76f9d4a9c165fffbe1f3b7bf7ffaf5cb1f3f7efbfce9eb9fff7cfef2e187fafaf0dbb74f7ffdfeb5fdffb37bb9578ea55eeef6e1e548f3e51572593f62cc39a5d8bff031057f5da18e17e5f2aed692dabfd585eacbe819eff165fb26949a624e30d0c7e0d3956a2ca9c24c753ef7add71de608b1261f5ce412c57095bafe632f680ba5cd9070154cdaf5c92b5f057e95dcd6cf86b853bc7c4dac07fce7eecbe7b0ff56f2cabb90d83879209a430ab5b6b7a9d269273c0bfcf6d21625b45e2fefaf7be385ba52d359e2ce26c49a021d215b00577fef71fc2bf9068a4b6c74fa4c2f7b7ce16e452026b61e42f2a5c3564d756f4decefae78255f052684b7b6b68db5ef9ea1dae8fad8263b13d06e040a24f27a2864183a57fd1b52d3ba860825023f419c66844d674575dd4041ef78c7e0e577ed81273f89f675d30e4371ca09c22f4d2b380e7a533392b9d02b2da470a68d4b5bcc9aa1004ce56a6ea0bde84391d5d5d8dc97ab27dcdf2f5db7f98e518fb849c97a81001d38b369a407d9bf632a2ebab684b5aa4688e0b454b8d0dda82f060e5a0e1adbc9e64ff000a68a6f422bdb14866e952618967df683193724039b6f40c2c01f4fe7384190ce7b9f7cf7acd4c011f567862633d44cdd8778df4cdcd4175ebba20e88eea7c87539fa12d2a75022019cb18959a5e9e9f62842381cc48b0e8a55937394a9dbbb9141b95797cad3a1b16a26110ae0645e628d6812570052b4f90b7d67a707dd061f82ab0a2ad26208d106ab81cd5cd5b3db355041c8a66034b6b1d9de3b2881070d3b43103a2d51414360665e943f34cc8c5575e43d010b6002a65140d7dbb9b8658465c37ea5e04ca7d026da742113f12f25399485ef597912f726727768726cc310cc6c77c8738f215e9b1ca49804a51fcd2794e80b1c6a0b9d9ffdc3b50e053640cb0dc8730d28b64f3480633d07db5e1787dcd161ca105fd24a85f7e02f65c26cb134f2c598915fa9f14d76305e5f29531f4f7d97232c269640522de297263e7e244268fd6d5c7f08f7c39c07a4cd05fb4ef1b10b9a0e71e339272f5afeedd919b00f04a5ce4365b5d226b8d73ee4b84b28d3d53da539217363ec6a65934babe6c3eb4d8e104bdbb2b984e553b75a45c23a3d6f9e49ed4e8cfa4af7f48c5a96954f3ea011a3022c5094d44380e584e21800b4c6bd87eac9931d27327a6112634d72d344c6e031a75220d1f8b79f17a03797327210fc393d4c88cde29a58cae5a01172e5f5b813969119dc982a2138245f9c10d11db4746e02b92e84811fd736f4f5774d2b87d6128395ae949b1bc4bb1499ce46e0c8cad62a7b3eff6212cf2d54ad0a53e5a7164a42b311eaa41858f135e6cbd5e12c61f745bdd7b2b9bd451b0ccb867322dd551ab85c3221810637ba26e75d6b7d691322459ebd8037db4ca0f8a92c8064d26373fd934a0daa7481f29269ddd6c2742f41ed77894f6dd69296938562d4202026fad21b5085c3bad61a603f416118b32fd92059305836d52a030215400bb38506c0a87736783889b012f74511ec7b500f4fcf8c1d6549c757ef5114a439c64a58c9c327e48de1c6c12b758cad652d029ce87af2178c7da32a77da363225c84734840c965cf062b982e9fb97982beeac68a33dde6e632f9daebbceba16d8eeb22c550d58601c463b870d916e51570414e7899cf4ba13aff9f03a5165e7bd30ea31cddb5f362664e7ee7b2b2638518b04a97434a3914c33668e3ed83229a54059e6889e56a720e81158174613e604fa56c44cfbbcb1639fad57335fbee37417e9609844e52a31ce4542a97d6ead64d092f6457f5be2f1b23757fd460d76ee3a8beec397da8b4c44dfeb3b9a86ad65ab8a6b535ef557617460549ddd70585bdb76535b080eceb44dc2011177874d85e03379b6f659eb4b1dcdd9ca68028cf9a24840f718bc74999f0f3fdcd266550e8621cce5ebb25762eba8a22e5ad2ddf7d10cca61d424fce5069eda0349460b329597cc4815ed596d869097d7fcd434c47617fdf8a69ce86658edb621b66d51b5483e46673b2d872ef80ea1c8aa7a0d7696193a994d5b4da2bb42cef8656e26cfad7d1c7c63af4e7d18c5bb1e52339594e512949b208768f4cc463b55b734a2b7833b63e4c3d4ef3a8a704b5be15043d1479d3313e4be58f1140ef38a94188910be6bbf8666783871da19b27601c5ae83888ebb6185b2d66bd56dbcaad56fa120aada3c9ac458c7e12d4891d2175fc528e7a938644fcaeab1807f77435032ccae283faf7283de58dd335f32415c1b2b52f7e3ddd9b1d310c517ef8a0f57448ff9e26101533e8824dcc72e28f71f126f5657a388e4ddedb2bffbc1219714b4db5d5faaa849c28927fed10b0d0f912a1117b4146c02d65b99a73a6d77b6769025af0201c971a61b93a6354ca9c32c183d7ab3e9759d49ba128c1b92b4562a3943c7c4617b3be8d1d91bb20c465681e3cd1ee8260f4e5a814dc2185eef1719343bb403afe73a58817dc49f9bb9311eb8847bc7ddda18bc949d1bef335c1c099d093d55b608746ea4f67e7c43a835753d2811911bb448a3b8ebef12f976f14e5c45e448219d2ed594c61aef4cc65b0927219d7daf84265747afb74a8290d73c5cf8017476a62083f61a1bb315eb836dd69c9d4b4c963ff0458f0363f2eab68eded59c7800a3d39acd6173173ef37e2af0f75c49d04e034c786a178ac9466d7438e772286b3ee6572dedb8c6e93273b0f3485e6cb7980f8318da7d4f95d714ca0c19f6119dbae96351b43dbf5d03cd1a00561ce4bfa7ba6e436f0854699dcf82e65056a1cc622e910c4014a35d8fc136fc9c4568a95e7c696c07df1d4b09d77baa977928fbf7bae62e3d30adb488592e792c321b4854e639841d7d191481ece71bf3eee2b8d424edb0e8beb77d8e62cd1b9c95d2eab923289a20cad9cd05d08cd4b2ebccafa710b511dd3d24ee811e302ff692fac442cd52b7dcc4a9934e6bd360ba07317c04bb6170d38c035169a61a6f7727bc3ab0032f73c40e05840fe7da608bbf2b6d2f2ca67cd4f56de2b920f02e3cb6c79277371e9c22a6ec9be9aab6d917c4ae40910801dab63d7e49d6f1888271af496b8b1a20bf2387ff3247fd1c7906fbb99a8c7d926984bcf621ab18cd8042bef330335c85b1a36655896ed4e63e13dd36de4adc57e8c8c77851972f1b8c3c45e1bc30a5df0e87ca666d77cd4b0130dc5d3a73c78d844cf3869c579d09be245ea43639eb5e5670d7dd90cbaa38c1e865d711e781b6de718734d9a408c5c2d963bd91bb58dfdc6a91154d36f05e1a7a1eb8eb210a38f436d29b4b5f13b4efbf8242974b02299ed82c10104b32f6ce550f5706895282b8c365f6d9f33fdeda1d5451453702ab249ddaf3b76f1af562c2ba3325add5de0ab4dbc4a6622d1342a2dd5f1cc450a9053e3a6550e99195bd707ce8f68e4cf6cb7fff03428e328361310000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/stress/128kb-16 b/cmd/precise-code-intel-api-server/testdata/filters/stress/128kb-16 new file mode 100644 index 00000000000..aa66b1aefbd --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/stress/128kb-16 @@ -0,0 +1 @@ +1f8b08000000000000137d5b5b8e253911dd4b7fdf96fc4e270b40ec01f101232410a2f998e92fc4de093b5e279c59a3d24c57ddcc74daf13c7122ee7fbffdf8f9ef3ffdf5d77ffcf1e78f5f7efbe77f7efcfaed0f797cbefdede72ffffafb6ff4c79fd367f45ec787fe9b57b947faa4cfcc77f924f92957f9943ef67fe9d3d23d3eb5f6deda68f477aeade4eb6a8dafd0dae3ca69ce7d71a632e99392ee2bf74217eb5eb795d23e65cc567bdb8bae9fef25b7abcd3adae4d7ee2bfea9dc936989bbe4b15f3d5b2ea916dd44594ff6bc5e9153591ba8e51abc5cf503e90fdfb92f9541ef697665add753bbf781f3dd6ad26be5d32fde714e6df2ef74ef3d65d7fa43cf5c793691d4da62baead5f22cbe9209788bc7c434e1525e9b48e7b6ebfa7f69654ed885ee5be590591a4bab74d3baca7ac6a5e8665259be6e15fabe3dddb9b000f3b8683516f6804dd951969254402ceba23b4b6808fc430b567a988f47c640f2a17b1afd56fc44fb1aefee50cada5159da9ab584ab392849a5879fc17b51f72d6fd96ecb8df203bd1538802da9b6b33dc54dd91c67e985b609023dad4f9d42e4f3b00f7e07b89b59f0fa5c7569d225710cf1a5fb5c8eefa9b5ccb805341ed6378b498f497ff6d9e08106b25b627f3f1d6b16c46aca5277a4b7b4eb6eec60879a4b02573203fc5e522ea49b2a778e72e75bd7f293eaabd77b4a5b6662ba9f164bd6994851038e621ae8b3a409da913fb7fceeba76322bd9b47ce8f6e09fd22d39c8b88f75e860471c75c2c7a6e353a6576f37494b549edceaaa5b9a4700b2c3dc6f0b576ed94ff37a081b3d0304674e69ce214f8d993b057e3fbc4a9f44202f36f33445aee50fa7311340215ed75d066e56ee51c51c47f28fe57db4cd25c99dd2dcc43c1f1c9ef0c9735b776de9a267b6905770ca5b13729a980a0e917208b34069c9057d3738dc8eaad72cfd5aca6c23d544679708926b2f770cd6c3ec2ce305cc9b76ce984c7ddf87afe125f2ad9429e97d463411b18ac32acd70f2990df587d538d34db95105c839dd9ef545e523125390d7da0966ad016720e1938e979ec74a54f27763013e520fdb5f4157dd28e45db39992d2ca8114404c09b460e6e8d3d6c6ef449b87d3926f5439fff73c2f72c100a238f9b549429ed34fd3305b967adf2141ef044c6fcd256c5001d2929941ab440e53c71247e90e0746a587b71840d1ecd6b9955145a3db17c9561e660d39598c8a8270977d00a4923597d8efaa29906f608b2d12f30989707ab7c0b7751cd5a587e2135a9c0070a26e82f19b7ddb72d78095275bdf957a2d1abbc9ae3aeae7c582d142f94db65130530898a29803d906e17b88f48fd9ace9fee1b7409c03500782b25f0ddb0058a16d2332609f471f8e5a4e6426a3053d03124704b7fca1a47e1e4b1eab779a6341614bf49a8fd33db30817a0d59d7abe199c4eb7a247900a91bacc10c5c3cd8038746f64fdcb54f84c17833496d57ea1c6e12788282b021cc86e28f4dbc099d0a3e782859e52f49980c693a065de3bcb60d6a67e4cf75e3d39d8386d0815efb593d73b10880fe017b43e6ca9fb02a18aeb04cd07d75fb1904aaf55df35071741fdfab3d6e895de9fe267b6eede8905474cdca6cbbc5d81c0f9a0d2e01ef20cdeda456d0780e583f479439dd5f9f9e1e075a97da7d83c0cda506c9a5709d9c6f597f769538b42d1d5656515871d360fb3d465ed8a807c59cd44bcc5ba0f4e89e482b8b444024169dc03a2ae16992184cd867f5d034a407b746da7f8310cbf3d4122d81d195d4f94ce15ca1cf71eb0615fbf5ad764bc9e8367c457d8d5d06de1e4ee01829537b6761c6df00c85d5b69216f2a7fc7e31f017dd6c4d50d25b5a5fb957f425a64842a0b5ac2efda22adb225cc5485de596dc15629085e31c50cbd3658eaace3cc21d568fbdf45ed248b622bd70850aadaae242eed0be921da720e2105b0791be17748c283c6ed3b9cb4b965bb729eee645f699141017c21712ede48e823a27cc95c8c086c3a34057cc97ddcdd34461cb660ad15f39f66f83c3a47ccddeca713bd8e63e99dd98d08ef62657ea4b571a4ef4142684ce54eaba59c18c0b5bbfc372d62283dc285c19ecca2b2078f63f2d9419030ee875471253dc77ba3953a05146e98193f3c135ecb57a2837e07d20c0f442e8b1686cbde06e5260899680472c5a456605fb779b2d817193fc978d50514da0a537f52f535da9147376cd37ef7e5f4a110db315f6f2a362d440bda32ddbbb9317e14eaf4940782d0f790b267dd13f692102cb60b5c056fa0f44448cc0c921faa4ff465c5219053008f9c8689dd94cf5ee799b4aa023b5645c205aa5d4a4a587d264af759af889a187b34f2864d4e6ae0cf4293bab04430d01ceb64c85392b9bb29435708b05c420f105edaa62e7173b5fe3368cf9717dde8a07497ed109f150bca034e050b70c6abfd2dc894c4f1dc84939b914c4ec0b1bbe98c37f1ea94309b5c4af472d188fc5f0d52d22ec5bdc3844032f75121dec9e9b6c9e137b037b1bb7979bdb251623844a3fa87716871200e6b427e4379930b97e3aa18847f6c2674277fcecb6c528f73502a96debab984f61dae980fce657af926c16a8f6248ef761d01b0b3576a7012a60077a03f8ef40da6412ca615eda02b6f501d086788fb5a0f5d92fe3e91352f0f4c0d8c52de2ef01bb9d34b690adc2626917068aa227c6acf2b4322ca3e9eedfa8ba79988295985ce86169b1d328778e3c16d4098d002473a5b283835ad0fdbc13f91e124fbc756e5ac1cf0b97f1b815ae0423d194e0d5ef3e2019f9aa09be62fcc07cd0c70e728a44bf20ccf282f3a8c13dacf1f7c6129d6731bff794297d3b4ff51b4fdd9f14f80ee53376613ce7d2991a9a467fe930009953e3a564eff6e20e829a35add681ba24d2ee9ad57ff3a121167ecc79afcc7a70483e89077cb55ec34481403f33588132fe1ad65af213c25b97976b8f84d17e160ea9d25349ef3aca28ebd772c764a192d9cbb59b1f8267d3c40dbb6bab75fc4e0d19e81ae52b9fa25282bf4b8321020e33594d082b41034c0a9dc590713dd80780ba4c7d6170c69621d6ad9afed92b35a655caea07ab673a590086949c56ef01d9584486b0f5a582313a9743ab784d521f8f16d09fac245b35f03753af69d471073fd88738d07d080b50664ab74e55853a0bc8b494328bd9d4dac7d87fcfbe7a715148eb635529a1338295129ad441f7fbef7ca43d260aaf4fa41bd49edb942e4791ba7e7f1882c789b39349231f582b76661ef6a11d6296d8f96fcc41cc8c13f4499eb1a47c543a5aac26945c8bd937962c9ac75e7f1e4481a03f6ba1bdf5c7f445cfcc26aa8c89e2680086027819d314c20cf7169c0a9ff3a3df6905933b0d967b1eda9fceccfad65d6ea3188f842411538c0f53ab39cea27fae744c894c90d83dcc67166d89f600ad68e09734a48d7cdfca0cee4edcc56d0b0ce9fcca717993927dcfe5be59bd40a27a7401ceee4af5ae825ae339b8049910411c6dad3a7643f215ebda55cecec4ee0b8c9a57d047ea51276694f72e33f6c0d7115b68f572d6edf5aa77676be5e67a1a0c19bf400b79ccdd2a6888d7f65566786c7ee5c89b135b5918a54ee9b8276e94c08efcca053db84993a6ba8c811fb6154b1f0a6a9d096a141eda037b46d4e6f52b7669a6d76bcb522ec9945d59b0670cd0b25d96b9577f11e14dd50ac65de674962477bcf5bd95aee3d716a16563018fcf45b6596b1e900282035ae67e1457d56a98c7a0cdc0dec478c65bdffc0975432c22738a64951e67df61deb8276b5e30b8a01ca7217c20c166cbf2c443c5f6c5c988eaf3a102069a31cf9b020bbba3289d80c0c065c504c360080e60494d78f278779ad6edcda2130066c3266050cb816700c99617e3043f71e907d94351095d8c9cc6b5e61c8ea2168aedf9e037384299d468bb5c1f7841e335f61506c36c550df1d0754105c9419bb8cb3bbb0ae4105394830e93cb2588abc5a62e78b03e7a01d975f8688a9544495bf90b85e74249c689bcdd85b2c116f743efa57a3181732f2acabedc262b4721fcbff6d9de096b4081941b67ef624fa3dd236afb8883467176e481917d0af911bccdf30f63bd23981b0f6fab6e7841ba2d4f5e5aea4fe53a4d2be2522c48c758b669f0668d1e4ed284b3a95f878137a8dca511159fdb3718ccf022eb4d033cdb0253b722aae7fc5f817e597a1aa4fe9cd6078dd57065eb67cf13ca83074281f95004ae5de97e1507c3556d623d85ad53adc268b0d18e318e94c47661034571aff78876c38b98a4921fc8dbe66328fe150f01a4e0511a67d7d2173f6fc5833b870dddf8c8b24c1b8696819bb33feb47d25d2e325a3a448d655b5d924a4eef708684ff514def11cadac12e2c86de4da705d8a76b09fb18ed31a7752cbcccd55b3646179aed4dda566b3866e98f42bb59c756c28c0f608b397abac228608b8865470ac54bd2b3d964196cfef5046e738e673b9d7d586358e1ab23eb30601ce749b66bc8f8e8414fc08dd19a35181ee51a0b05eb87b33da58c958edcad125a6c00e213303609a70e420b9217160d06c2028574f458e3d1c96a2acfd2edd984af4e863d6f5549c4abfbf59097bddf09ed0b02a8e94cd56ff41cc1efb4ba1a3304479d54b370b087d3579515e1f3b31ade11fe318dbfbfa670124920c6eda336605cf664d231cd39907c075c8eb7edad7a55bcdfb7b5ce1cc347060dd331b5b821c7996ca4feb35f8d35389388f767d6051d23b0e0bdea6d1db132c7d89883aaddebbe745232bc1e7a042c460ef2670bdf23ee26fc738129482001719c00bdec11d557f7906b55c3dca633259e285253d4ba7068e0a5f5be86d20f9b3b873c74e2e77562e44dbbe6f356faf791de6a8de3510f6e2b9be81afb9f37495fb5ade3bd4e631de656f5b4dc440d93ef09c7b0a45ef24ead66219e9cd1efb63cdd29369b4c96f15b495abb172606c6dd6f6f888731ae9d025cf273dcbbc70d23c1e63faaaee32ddf1732a36d5c587b7fa5025b572151fe3c877a2c1271cb8904b2bef883a278cb51f24d2dd2de1dd3963c08646988a830ff9654476675d299398d1015c38f3a018020033fb7e95650e6a2e96a64796cd4595eba3630d30c93d86c47cccb6e11eb3ba5dbaf1bd4af69497775a94edfce03a954613bf4f0d9c3767676529856526868c5941ab03a0d9df37b4c75f10f4f047729deed80de17d23f5a4c3db0576ccf7c0ec256dc158d0aa2983eb8dca35288ab02a744cc634d07e98d9b4c14d37efb268a8330a3a2467b292d60bc5527b974445f872dec64478b0c22cfca8a512b50a242b283ef63c52faef919b490d993533704056506ae54ab93a0c2fa830a0339cdea736a656748e490a5b9f380db14274a5f046ad0ad8df783d3b1abccd3215bd179825c1e0d7f8d32298ac7fa0b30edb012f04c799c955e1cee97c9b1356b05fc458b3d25e97a91a837b3914253afe4d46b7b328a21b0d9c8c1a6551f5f45221b5dbeb7e73c7b6883aab6ba3400ec893d1d1e5eaae99d2fa78bf2840efe434239fb3a5e89a15d26995f462118363626d351aa040df89e4b631738dad43a4fc6c3bb3121867644fac4ec38173510f0a5f525f4bb8b7c800a8f95e37b6f9bfefa7826c779192dde98223797c6c976f0e73391bff533e28cd7ef7d41cdbe211a0d4e442658ab51eae9374640ddfec10c3ee3224ec36e0a7c07632fe9ce1d99b99ca0aec4f2686fa0a7a4f540cceb67b9467697cbd9fe12b07e31500e8d48a8eab9c7e2a28a46e5eea90c99c2392e3c00b7051ed32fd43eba60f5b50c69717e9c49eb9a70fccb02cd3ff16481037de9abdda5971ff9ee0e10954ee74aa172f207a028b762fcd6385b644fbb2d86db719a45e64751144fa8f718831d7184c0aa6e9c79a7238f177e0f9dd14750d25ffef77f6ef768b3bd3f0000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/stress/128kb-24 b/cmd/precise-code-intel-api-server/testdata/filters/stress/128kb-24 new file mode 100644 index 00000000000..d1086fb7387 --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/stress/128kb-24 @@ -0,0 +1 @@ +1f8b08000000000000136d5c59ae2cc771dd0bbfeb02390f5e80a13d18fe9008031604d31f24bf04ed5d310fd50d82efbddbb7ba2a333232e2c48993f5cf5f7efbf3fffef2d7dffff73ffffcedd73ffefeffbffdfecb7ff4f6fcf2b73f7ffdc7fffc013ffc5779d69c7d3df0ffd9edaec2ff2ab736f8d7b97bb5b99ef114fa8f7e57eb194fef73b573ce33fa6cf09b51ee820f4f5dab1cf8b9f6d1eade633ca3b6f3d4f5acddfabdf0a8f39cd2e0c2a795bbebbaf0cb7edbf3d34aed6dcddbe8dba33cbdd47b2e3e849ffed3ead8e3f435e8096befddf036304098d44f2dbbef51f1ce6be0c5b59f05032e34bc75f0bb4707d6f016132e851b9536708030b95b46bd8d6ede71920d2e87dbb6f0add90efeaad87fb5cc5ee513f8425b30caf1c045872d41b39c2d8d7e94b6cebcf0e9c1e7c143070cf4e18982e1378e8b7e55cb38f8e368f31efca6fc5dd80260cf02dfe8059f0f6b32c78031dc058686b1da073087514abff00c5f5eb517cc1e4603eb38c090fa2fb5b9cea3b5765a5f3a9b436e7368ca7be1df6bd702978225cbc221a6f9f6a676a67bee32d1fa6d75b8a3cd108d50f88ab84895976ae07dc12d68b9f1e13bac0198a06e5cc1536699e8c46db45bd00f561965c00ae17c273eed9659619dd980688479faad8b278cdf432709a6812fedda4bc74be6867b9d0a37e3f55c77e20ae0f4c1bafb6e5ab88acb0593bdf8c35017925bc3270da602ff5ab0c0a5918f8c5dc11d1acffdabc7885ba9b16c650b5b88b6260c654c72c2d36113b545ce9c6c99ac8cb308332daf2560c7a7cd81ffc10dc82367a5fd5e4bd16d4f1b9caeb34705cf83cf65eafa213f801ed6d8e8e26b787b58c15e16ed86aa168149e7c814d69d3c163eef2becb5bac650df4933141fe45d0711a2150d5d0356b094c33fa92160a5c0af06cd39c4491ac31a7619b846b9976200acd3c26db44befec0bfd761f57b236dd96c2189b0c9751b6d10953ec754c5e3e8d55e015d307092b35e1d9152f5abab27ca70b1b82b730f93b2f9d2c032e6b9a0d7c6d726025a7e71028e629ec80601edef0baef71852b0c04678b4fd8f024f14ab617fc167c1d57069d18ff58959646771a4e7f80a3fdc058c79ee80bf874f87ebb15d28f8ce3b5232704f48dcfc15134f123715909619a032edc67d296189a433a44005a1ddd4078f379782f52a46b18c1e992e27b0e622ad806a205ac6e1a51708512223f86175b457239f0b2b669b160daf04dcb21326730ea46d350bc5213da5ecafeef9b6dcf71c986747d08c53c942b9904c281c5efe056b2cdc47860b93a2fc567dbdfe40d4742254282e0cf6c1a5c071e152d714845ea452960a1b1304dc3dd8fcc7cf60b5ba8a2c7a047cc1293529c2c3d40ad0d9062d6ed71d113373a273f817c4962da2033317268bc1f26f805fa6778d8470ac72fdcc65b44661eff2dd7e74dde2832c6fdeea60f39b8d76e590e3f2610a67754c833cb390a36e0767d62fa52cbba0fd1801ba3b53eca867b91e7a143547a1c9983775e8cf636cc137f0879604894e6551cd78d34f5aeaf25a60539fc3d4ef3e0c8f02778fddcbc1338deaafb2d18dfa4c41aa05dbae93c0648ead249d3907f129449a653b4883f81a56fa7df21bedcf7e096d1bd22736dc57253c91806fcacb729ce4fb833b84c718be87ac4dd0a68a5f65ed8d3d91ee5d18d6a4bab7b29a561c4cbc15f34d3e036a087e2ded4b8b7daf8ea65b2292b5e7617a562f020f8e510d09a1c4002b7649c357c0dda3e08fde05accab0402117e02ce06908fcfc06d7aabe3c87938a19668671fa1ef6ad99243bd181331fe28ae4516e90ca73cb460e6419bd423c9003d15ac50391b945379b507437b2a05380fe94af11e3a308abe79497eead9800e198a5800c88894800ea4abe5d0061c0503d8648b2a9e1f6f90b821e42baa11e3f28a4d7469b123393b38585b0852a426005c1b02cc1de84f028675c7755817708de8bf0ee3c02ebd2284851fb16ac0d5a3355ae847f3550ec88328361ebf8b6caad6ea2c0c767407749f935ccbf003773ac4e24bf1491c7250b5c5fb984b13b478916ff6870bbf4ba3d5f57f6281b1c61a3146e070d742b486bebe20b78c92d2256fadadb186c24cdcac9c2ed0689cb2c2f30e831fa858a036e5640037433805db6486c489b698f5484ad7189bc2a918e9948f22acb173db1463d433b88b435e34bc952a36db4ebef2543e42dd7325b6865f08d05b0f8f8e36c0b71d4937a8f2b1dac2dc498daf13c12163585f0917c12fd78871884dc9938598781107401459143b62de9998bb0c1361e555db2ba217893e34b5d9255c511094fd1223304f5feb7144da7877b86383e2f92e3035fc4f21a718e2e4780cd79f2ad1219435a18ca45cc60008ec83184693a3967c04ff7a181064acb2e08977a56cf7ae856524581d48998dd728cbb06ccd4bdea2168ae03eab1342a152f007b615ee775a7e7bc8426e064229a425f6dc8160afe38a67ff55cbe05d872540c4050a30c709ae810b5e6932c502b99ab6c91f16d23654d8f3e5828aab244c0d454b83003dafc5598cd868e9e0ab801cdb47c87e67ea0553aa852e0b5be944128cb2a6169334665bd58fa2723ce2e4b7da9a09521266a4216be4db9bf7b4bbf3927fef8b2610f0ea2939fafddae7ce760dffd055fdeca1ae07ab0083a00569652efb32b92518a3516d6de947d70e2c37709474fdec589b244c13269c40d1ec2b6eea1b40f107a06e536c48c52b7a3e6277d84704c533343078495e2399de2ae0b9c04d61bdcea5f20be02dad9a6e1279d0a22a760cdf3d3c28a4c16a37a00325c47ad304860fe157034ab6a68692c501d76a746de5fd17f6bae372998d3e76d386a89d83d617908910b911c9478b594292735f862c33d498b3767aa00d31c62ab4e0b610f12c0a727927a0d1610c9bd9b14ce088c51cc7478cca3c3046984e26d92dcc07c363aa2446533eceabe308d93f3856f3ba75ea4417e1a58309147bd2a9eb1d9b2c8c2e1d2fd5f061300813249bdd9b208f104330d8cea18590ae2773036dc9888e8c8984c218c4d42453db116215254efcdb9403663718427ba283f75095024fa560db6073ed16ea1eb2f3669b102b19e80766e82c1661b94ebb8b2a4b8c9d195c54c268502b668a1dea4d2e9ae097b3750435e349058e006708571ccba420934d2015ac8312289cba5339bce172b9a88b67a45f6c432878c7cd06a0b8ac42fd04239cd3cec572e05088a7c0c28f59535758125131c3ca835ab6a3b829f9e4d98485371aa314453a143c085b5e2a82a61475d22321f89ffa145aae2576041257709e37c729ec18e71ca6c0cd48ca9f36f0d4dab000e23dbb36d6978b4b449b9d8601a3dd90992b671213cdfc57293248a5f65ff0b5beab5a211726cf9c58a8592225515e40a8a7e2fe63bffb58356120673f90c55020a301086e72e66831ecca065e90137891295093e5d044800a18faca9ea15123562abbac6135703b4617688efba9991121f424256383007f2ae6a2d4de51fa58131e5729e32850220b1c591273991d989af04ce6d875e24d66477ba968fb8dda71588fe260ebf42413180e4388e8dc5c48bd683921fb4630732c0fbe10460331c56a7773898f2092520981c309d1cd82a8729910b7bd9fe549f51c7712eca288070c21389c27a00822219c6e0e979fbd765fe674480e635901f7814d6e0941ee8f3b033000d36c00a62e3529df6e798450981c682e87126a08b41111a5f8533164c0d520a511da75b43fa910d2445914642d6c11a9753de43075081e5fb82a24cb41dc83cb664c93a36abb493fbb1ec4c12f984d8a3bb6024e232ec2c926da37e623e2ad95d7b05a14e0591935433d92d0b30acb816897f357aa710ffcbf62642811e732f79e3b86c19ae0786724628e87c7d4402e0bd1ec68b261b34d17788c61881cfa2854f3c69e2b38cc42ae8da6eb3789d6331cadeb5e748588ddcfdc3a783e36b38db3d1cd1732e7ac2ddcdd89fc01351b03050db7dc2d4690d06f481652ba4bde87c7426a2903a72b7db59bc3ba12fd4612867cbab450e3f1b805b8f5eae1200022818a43c33fd5656c67aba7a451753099a644cb5b3c443e5b77b0536047a0988a1c8457d9dcf0a9fc7b3323a443402a969964519414a5888276f7e5e80f15bffa84121b9f1176408dd086f6b5f479ba40ced6cd45797994503d28c91279e9d851b20dc905944a239e0e8e50b9af4b43c49b1b3cffa9581ddc8e8d7ab1cab11c345884412517a79d6e554dcccfe8ae10d3c639f55170877630d265c600226596a1c7c0825a0779123ad1882fb10f00b60f8cecca65867274736bec15da581903cb3721c0a04921b3cce5fcb5a7db10ab8d09b4bc67248806f9f015aa13a1e4801c31578d3982d7964604e06c608f2d168d45484f6ea3068ce22a126fbcce39259439edaa0852dd6dc7e45b525551b138be8523b1e7ed5b0e2383cfd648fe2bb4b1c862d8da8431ad14a30d36dec5ad4f814264b5a15d8488edf41fcb4879838c022ae6ca181fffb5d38ad35403f3ea0b29558c360715a550edfb951c155fbccdaa46483826fd11ad8ff89cfc5ee2a792d3d81b6fa8f5195265257506f639eae2c8ca6d8715d0fc88438a55a5499be89b2df01f6606a950b82f28a20eda27adbd531fdc7152e2e54aa53ddcf55764ac54518c74bca59e1087c5dfd11facb0a03e698d3ba972b9246b42b0dff92dc3efee27c4f0b65831a39406004c73e8e4dec02d2363a8703f43bdff22f290012ab6a73a3911387a55b642712b5124dd0c81429d53b9bf1e6f175aa33422155949fc24f644cd8d8f08a38d3b53f7121362165d7ca9305b13195c9ecfdad573e0c1ca6404b2e1a8c4e894b847cc9e8228448097c97496ac49f74116da28b1722f373d5da4457f449fe5903ab4f4886d3b28c328faf1cc97c77dc9b0155c777815e1ba12fd7b915e8669fbd8ee8e79545b0dba0b8cbbb3a169f43dc124662663a63a850cfffe2495899094110579fec53020796d6881ec643cffeba72e28cd6bdbfdddf237869c752ac5ba2fc14cd54ce56a0a88659a950e52dc46bc677682b18b77152c1c58d5e8a442572c47e0089670967143e6b66f666c575866684d5a46a19ca2105c47c44a124eb8f51927971dcb4341b02d29549a346bd0d6c8f0119ca90b6cc9e2387770548530d6e18d3c8240d42c924bf5bc5801933d0e76c0ab20e60d87f052798205a0a69686f14c70bce42c259065579af2f11added38bcb919b3e47bb40a4d134bdb392f506358b173a48c04bab096d4647f8183d149c3466f988ba60d4b339ea95d454cc07d37749443aa815eca079a487046f470c51b138d982891f3fab7b0604104b19173c436b1d279c5a0ae97d72bae9e1730d54136cf6e10e1672b621c17730511e2513f17133f6cd8837ae0f2a8caed4d7e672d919859c5c888014d29268a48d7f44ec049e77c8321e8b8c7e4201b13d3d9cc35072c5202851b3bc085355800474ae527420dcecc873507b1394d8c1a3624b92026a2dec22f20659c7779b8d1b05480e5f8ac319c91984971c71b04b54a5808d411134a47f39a473d47a49b195fd81e35e8692ba0aa1673686e66b3da007d65eba20e8e7bd15afcdd89dda44b73cfd4f0695d7637a739abc9d50ef2117ae22e42d0780e41342ce681cb14d91e2bfd2d98250ac5ab668d4c993895fea2346b5e0c86b76dac221076007bb34bdb1b4cd352fc0d05658c1d5ee01996d2da0ecbb2b254e305e542c14ed06d88cc58afaf0d34ee752faad6876db7b0a5ad9e56d532206bd8e58cc3bc0786c1d4b280b4479348892100c701e412ef71c5a6b61bb56b6e5872621bb7ad62a52a62f5207ed31bfa3e261985ae7a29bc3ba8a058ade82e502be20e9d28f7f40e7b74511e1b40e4d856a9cc4f6ee2a7c33980b914b35a335cea6a66f687caaddb94350ead44b819603f8a33ef7310ccf834292d98c1b2515ad432a1ad298c598237dc278aa7882845a2dd2641ac1db374f239164c52dcd3271ce33657689e442464252001892cf7431e7fa96ad824abf8db75a2629edbc1e64467b4ee7d7e64c92a20b88a7cc312b9a78ee46dc7c8c40872e5e8f66a3451e1f8c69893501c0b3087254ff118a4b7e3723ab8a262a488998dc3b508624540a20b7a28af1d1ef33e5e24fa60160d760091f93926b84f79b956b51411119050c2dc89802577ae93bb9b54d263ac4c04a8fa83e666256f3577f6ab5a0ad703644559ec840b40979e97f64a9a091f75214f280f99c8346dbaf61a325833a468607bea1106214fbcb90f08195936515398484aadcfad0a15bcc9b4b1395bcf7883bb1a74402a4f76a148cfdd9541bead0a7a566dcaf803a520951b9e1b48c5a37e81b6ae3605557a624d444bb9e39d66d2c8d7e2880e9f88172badf74e006aa5838dac37882dc9bc226510ea514964ca3723d05f3167c6cdca4fdad87a61c1dd4bf11ebf899fec508a53be840ba03eaf9a6f85d509a4661cba55065e3a5b04cf6b1cdb91e70eddd8aaa445bd5a22b496d0443dc6a5a4c3248c163a781e730b4ba63131a18c8380d9fc7ed0c4ba33386a131b94a43d2304effb84f3a8b1a1d2c24ca998c7b2deba6f6d4238ec5091b31d53a82eeb8b6ca0f192bd157599b529bfe70351d26a0f6c2c46e4b926713fac6213326dc582c0052adbf6abb5ef027703593f76a4276577d4d0de5e21541163a62146088528157639b1588fc3d2792712d276d9f93ae707a98a0b8c02c6e711459c81bbd5b3650145a9d488953b1161b1d8384b2dbd61c59df8979840f07ee45e4cd5a365f10fa203702c9c064d676b21c9e4881cc2a198a309c36376958538ae06e3042492b8c607f016144ae3265ea2385a72eb0dace5996b06038e6b3dc75459494c09985dade6fce44a056e246bb1b7766e3c8015840cac039d572434aa2a78491b59c08cdcd921b44ac09b2220de64ac78c825dc84838c099c50510b81a3200dc20c36ae1321984f80126c047f8c91e32f179aeb85b08b4a2e8f41393efe74f2a46bee5ec518a7329b4c9be0608630e62502ab6f328a985ff8ec81887a86e7730ea646e6c50d01eedc75362883a7b2bab380ac57a2f9bdf7efb0d7b8b774a42bc3cd1836ca13152cc6f0b3f4ddc83e9f61ed12524d8182cd9cd9623c6519595475fbd3a81afd41cd7a992cb4077c4fa9ce7a598514828b9a664f38038cb90871aa56cc3c425c4f6b7727edf4731d721adaa7cb48abb69244c3662e2d892b87b6b40bc0f4628bfebd9de0d0b6a5319c213f957702e4e203c24bd25e29156a768d5d40d9c4438375ac0ab9456a6a447505552824c9122f126e13516349d209dbe291021c9be05837bae62850ad10476a406752e71bfba31d702a5da00c65150041bba6fdffebf190621cec023c21a6e629898cb52477a93cc53884bd44833e568a343dd9d8cd2323740811dc79ddbe65efd06036cb0a49dae161c528e9730f09a45fa7e7e41189b3139044a45c1273d480595d9241b75205bf151d1003cb0e2466f32e8803faa0765acec6616821df45116d124d85732f326b63f59189cb352dcc19fededb181c39e819c28f9fb9fec84eac18b57e24357b3064da9e91f3a9219cc50ce2b564aa00f85897b6d45d9d2bf0834bcc3be48870827ac5688625f56e5cad25c75f6c2cc5cf35368a45c79d4966dcf8ecba1fbb34617352d429a5c46d2a3f2194617b50f1f4964347d0ffc7d32a722016afe45eb442a86098b794a80e3ed8a3677b543ef67a93c12a1fc88b06ce6703c689ed6cab88024f70500019e432c925a206fa315ca4c0e024d0a4c7ae38f631570adf66dd1d8983a21426c5827db65773f0e1a949ac24c7d0a9322f7cb21e029e214983ac1a71ad59905f73805b840460a5730ae3464ca11ebb2d00691d4d7b22d6e061bceef9526cdb5305feb7ae07f5093feda5824c911cab393fde3ec29bd54e9a0897ac2263974679475f4e1b54d7b0777aa1009d3f16cd246756dc1f850f8f07e0a060804a357bdd843f20d991a2be6aca3814920887df7590e8517978f10c5a59bace32a3e6f597e9d84458e00ae212e185e31e53750b627e5b43f1ac3436f870b9c16aca2dca66e8ae16b245901e7bff1a3d22f7d8790c2c856d1d3b8c92c4f8a9924a27ae04d5b37deb09ef4308d982cea2858eb987989166948847cd21c46613bbc5276c61d95864c02b98bac363f771d3c23b01fb64f167d77e237ad91c2c01b054301e3af428c08a44a73a672ec2e8889b1d72a4034464b44d4a7113be674cf6128ab870fb4d1745b4260290010fbbc8d4120ea62404f9648cac21b62d2cefc1083171d1f9b6c74f137f7b2109cbd13c2f7f748dc59a427bb5fc6a11ea9bbdb9ad62b954829dbf27474f9f60441600379f742a321cedd3cd4e07500a1fb1433a24713f1fef8011e720decb30a241705612c81996c4041be41326864e7fb1d2f04ca71bce7bb1304f621cda7abc2a56719c4a359bd98ce48ca7bd0aa7e73768f8cb60781c490a838a02b1cf1a3b0a98f8b0439dd29b73f2d52ed053b059bae43d624203e0db1cb75ff8068c81535df6ca15f4bf53f084419222a3f8a95ab2bf92053b62141cd0badacf31d50514af054613a2100343edb114e34092f0446a74c6b3ac5dae29023879ccb84a0f1c84bcab5a2c5423731265ca82aba44852f1c92f3dfeb0b5dbf2e5a0b871bb416a36e1c3f9da295a6565b1ef6a0a5217af15e3cdf8d603c6e16da6e29669097ed7418d2236801d801c31c2f5cea90d9fd8c9585f2476f9dd109348f3822cc91937bf11cbba69ba335ee779a8b13fca91cd3ced355895c1926a40b81fe264f86d2f66ab7835dfc937f1c75b94171579f30a69811b6652264391b0b2e0546d2f8ecde26b4dc28ccd07afa0166aa4e38b88c947e82041e3da22318562473e8a125542fe6d4c43f6161092c91debb3e0c0c24ad628695d46a8faa180c0be1d560f788c8191cdf8820d767f91fd68fa0f4be76fec42b539e44f64e3e1a995232d0b1714c5afcd1242a99ceeeb40b85115474e8e7e117b8d3602974af69d25e21046eff3f165a2de726e3ab337f00156d1e16017164fc0f1b15a4697a402916e63cdd269ef24e6773bd0c1225724abb2521189031d17f01c6a1d83b12067f316783e826aeb8b5fc3a7c947d12d69edb6256a7a0d047b3e97e8b84526dab3d8ebedcc33a5f57089d4c2700e1ba40a3d105fb5c3cf12d1532b96b9cac3a7903e532bca8e90f45253bb3af6ca51d35ee4e52384b3aca4d6de9c1d107d9df229e1b0b9f54c6203c66a5bb9c50e91b9bd53729b7c1800bbbfb7a68a992ee473d2b0ade53570e69b9a14a012c1770398a4b036e5aebc9d40d225f0577d0b1a4b2f5c1e270636f7d4b7bfa90c37caa1649b37cbc7107dee10147d6228b710a2ade7a67c46c3bda9015127643c1ea5c874bc84e3ff87e6bc665a7625baacea9926ee85e3ec35b55acc0aa58bb913137178a6aff0b983d8f72677970246750c6f09743a698df54f6c1a85575330998742b4dc08e577026af9802f8bd9271e727b215e92cf42a05c2f6d57ec9ae28b1bf9608949d861741461e449467fea560a6df32f6c963869cdc1379dfc8aaa3eacc937bf6131e88da4be9273429c0583e651deddd08f1e74ca471bc3016e3989127be07c24d6fb96f6d5d09bcbd25eec4252591e25c78b59e7c89fc951cb5c49d0fb6bb457490ce9a215416521841ca971e9dc47923478f77b7f6af378df4a13fc35e9dc2596af42682b554fa0da4bf1a672556bb8c0434f13da71187e5798f2af4687949866f4c851a4ea6b23df2b5cf30134a050c4f1279d2285e474011d0e3fc319d9b958cd1b7b1fbdc18f406847e5db597e89dd0c36c22969305e3e4c18df266912178de774e480242ef32d1ab4b9fff7bffe0d06fb042aa2570000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/stress/128kb-32 b/cmd/precise-code-intel-api-server/testdata/filters/stress/128kb-32 new file mode 100644 index 00000000000..d0579980724 --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/stress/128kb-32 @@ -0,0 +1 @@ +1f8b08000000000000136d7d4bae6dc96edc5cd4de17c8ffc703303c07c30d5b3060c3b0dc90d4323c773322c8cc5c550f7aaaba75eedeeb93c92483c120cffffda77ff9f7fffd9ffeebbffe8ffff8effff2cffff63fffcfbffceb3ffd87d17efff4dffefd9fffd77fff37fb8fffbc762e6bcfdfe8bd8edf9f3cd2eab9f65a7ef68395f31eeb677fd873943e7eed97475df6cf995ae21fd24ebde795f0a9b1e6ac65fd6aeda3ecd47e0d1f49bf96f6b01fae3ceceaf6dfb9b692e76cf8faacb3f5ddcb6f15fbbb3fd96e6917c3bdd66fa5b2dafa8d9ae6ea13b7dee5f7a7a45ccbe8bbe042ddee5213ee37718d5f19abd5deeceb63e6b496bdec9f92db6cab0ebb544ecdae34ec52d3ee3ff1547d4d7cdc5ef88f3d4d19bb9696fc3addee615fcf798ed10bbe5eeca5d2587dd802c47bd843a55fcf76d5cd17c40d6d19f41278ab3c5a2b29b5c6971f3d17bb92fd65aeb8635cc6ae6ff76829d987f0d5f45bd92e6d4fd8f942f6959a6d3d5bdead26acab3d731976b3f65bd55ed5ee54cbb4fd2ad556c796fc7d73dbae82c74f3ffdb397beb157dcb75def43c50a2ede682d3e8efdacd967ca59c0665fc7dec4bf7563bcddb48bd93b0cbd089edebe5a7e7b26dba6e23f18f63af6ee63ed660b40cb493bd7bb14301adb64bef07d227db9e1c2f6ac65d877e3cd071ed51eaca43d33f60a06bdb8485c92b4ede7c5ac62d49af12219ff4ab0b83976cf29f12b633dab66b7b6ef966e76f4c33ded213b6e3dcde2863d62cdad63dbece20baf0d53afa55718d8d9d38cff87b9d5863db367cdb3c12a7a69dd8f803d791dd9f662973cee0129585fd94dacbbfd78fc7a2b65e4d2780d3b68f6f2765d338ae97632742eedbba37153ec7fb94cbc2436b314589d7d8edf5f78c634b79dc2de6879c58eb45dd6fec20e47b1b5e751b307d561b2e5c21eeb42d5df085776df6067afec3d3a96ec2e66e5da0c3816ddf41cd0deec0fe678f26f2cdaf670bf90977dbacdbccc9ce3b0c04e477713bf9b95ebd059b84b754c0f2682fb9811bab5d9e3377b3cb7bb863385b72dc34cfeb377d8376c4936ef63ef66eb84e76f383c581433a569779a1917aa4b2b822d5d25db11ad700cb61676806179d53c453a269978acfa309f614b00dbb79f2fbb3d6da098a9d9d50bcfd058639d63cfd3b071455bc7661fe55b6498df7df05aed55e5f0cc63e56effb74b2d674ddc7bd8c7d3a42b31a70bab1972d8743cf613db0a18b33dd173c26d79f7c0e24d7b8c264765969c69dee96c1dd6930f3b2c76c8a3c959357712e304931308f2e293d986ed519fb36d966271480f6c6be20764659e345b6d3b5afc5bc419acca2eb20c44b0657730b7dc968738589b7932bc116e8c25183802b6237be3b36196f6b4a36379b79d1cfaa1d4e50a2ddeb57dbcac3dfa2a669c744be1ca0683e690e5c28ab42b453728e6bbee8ee656461ab8171629ffe02567296db4742d900bbfe1599bbd3b0e70b5086656c730c2adeeb36241fc05e0a98af6df7e92677767c9c07557db025e5b88a6bec1b2107bd1bcb154761e705619cbe058f01199d95e83873147c898fc0f6c2822a3c5c3c5c8c13369417ad08fe1f0b9f3348bcfb604a9c297a4dfb435af8aa4855b357fbb2b04dbc29b29610b75dcedc5f772e712ce88af863ffcd9f6087dc39fdb6bf65569f8b664089f05c7b16499c1d8e35d094327f00e6dd3aa70fa0d5df4316025b055f91f0f46c215e6275bea8cbf8570a0220ab9d7ab38737615db1743271bde56a6d71e0c54fdc074030a1bde62573dd8aa8c274957dd3c6ff04f083773edc297d10b029cfd1add469be649b89ccb2e2f6f0c036af44d79d8577093e379dd5acb011b0d400ab66e8b5a67be68237625fcaad9972d588bef153b83c014583b58addd7ec16f5a64b015ca8d4e737680428fd032f6e3b1a62dfc847bb69b2cfc2b9e914ea0655fa694e88d5b73d3c2bfb3459b72bd2ad1e7a023b133683727c6b2270124ddf3ebdee136f98ab800b0b01e6b10a1c4eace13e9334c369f6044c794e31289b14f165597c72a872ceb044783b22dadf729b9826697c4dae6c3969e0127d79c8f79a5dc7c1f0d89fcca32e745e8f3c0a609079860953c261133a7f928fc9dadfe040aa4cb458cd159b7b8950429e138cd4b135d1032c06598bba38358669cfb44c3e231d8c24b06a4b9885b6f6e21ae3db0d496b4e83c14a2045e65177fd274ac01373d96a16fc77ffa8621e41da0e23fddf3423ebb3fb6c052183b658676e419817133ceb27cb36d0b5edfa02f7daaa07a1f9d661bf10697ee13eef6c78bd9d63010c7df771e187f5da05fbb0fd0945d0dfb65cb761ebafa36658095baeca91890b1cae65501ae1808b11344bd8612133086d9cf9e557e3fdbb2d906ae75bcd559ec8ccc495e82f0ac208c00dc07f2469cb2e541b8f3550536e67e7b94d52747ec05d188a3420029e2015c1bfb4c2069aefc6739a29925722f5b0b2ea92d2201bf39af424c51bae70311bf0e1e9303da4002d701f909c2c14042c53391e88681751373c3ebab61b7c42d0c01667f84867a6c4fbf368cd30e4aee883630d5b9e17ef07c8635f170f2eac064c70af36606f60747cc5e8d61c076d82ed67d21075306bb121f3152b8b29ee3284ff43a5abc1d36e664d9665529e03f761c2ebcc3e16eb8347b4f5cb06fbde40515743f9936e7fecd50d0e09a3687ceda0466cfc46fcc68f07af6b8ca55e8af7f8590e94435b8f24034c9bf8be4cf904a0d6cdd98b4154102dbac0430e1ef9999df9c2d8af06cff3193dbd2451e4cf8e58378a6e645a65a90c25c11aec75e1b6e93c9b7e57799b0b1c1d10f8f1f9b2400b21b3bb36edcc9515623caea7002beef783b83eae639f0ad6ee8c31272bbb8d92be909204218983dce62cadf3ca9b23b569cd68f83213231e463eed5e2ef0d0f7679e2693e36cecec87e9056965dbabdd80ebfa0883f2b787ec36003fe5cabc6d881901ec96f695f3364ce33cf3ec1e0cd67f090649d292e966123c41c64b019ef7f3cd60b3569acf8b730b43d22aeec48b2b4841bc23d96ed4fe378d0e308d714609041bf261c6a9ca4dcb936375ee0ea76289114fe1878e8bbcc5124e650c0214a5fcc57988364b0310c5489012a8df841511501698b6f32432eca7cfd78da0e988b1edc0d5bb05568f3867c99f18bfb98000374380e28ba1d7af8babccb41740d11b1c3644a8bb0b69504d15a712a707caf17fd383e3be2f6f45bd9af5d0bab5c80b8ba2e9609629170cdb08f4a9fcb63a2c76cd8f5e4ef56b95e70c699ac43cf0e32e0d87e27101f4764c806af7e30c475fa65904eb27301d6e7f566b9d3b8afa12154583c5beb9a1b108bbfb0ce9fed05c3f45e0831666c7b1b6897470724d923c3cf1766ba7b31debb8f49002af4953da2a7c563b26bc2230625d35fb0fb43a1b5b2dff80c07683ec842fe3e3077a527f2c4e79014d8e14b85f495166cb9c79b08df0f97885dc10ed2f792d90482f015b2e5b47de87c1398c538693bcdfec095d8a5f31e2490908f02eed33321633ac0b903857003f6c9b4e0dcccfa999ff1f491744cc7ebe963ca459d0ce2520142c0ec2dda653d8dbff2da876919e685993a84a7c2d98699cd0f10033dd11e70756279c69588a92374e3b02dac601523c2b379df3e124c6d83fca72da0190e00674b97fb3d3e1119d360c82ac81e88e705cf0aace57ad412d9d78146b59d43cf9d85a39ac4853272c4381284e6870c82c38eecc4e4ce03b9d3625e9cb7ef091ecf20bdf99da41fc3126b794ebf39bf66efcab0b336514c1b391fd00e10c9485be1a888143e18c2f6783ec7d2d6d4a25062f0743abb3c6754b454e2b53cf5000436bf4d7cd8cced8bcd091259c8c1cf70904c97a3f66bfeb1d0d1019f6563848df64178db3f76e2cdbb6c38b0c5d59e7cef718e4a7d199d3595532f4f77145491c0459a39cdaf294635830a88360f2d6f6905884f8b1eddbcfda594b0f9c038347e3025253def43bfa0d520ee6a004322dcc20d1a04e3e97859d8484870157be526fc5b9d61b703b41c32581a36140b882240bc995d96f64bdfeb61b306ac3a16e4ecf32051687bbb9da82498d1bdc72af5c5084e6c2b67ca7911115dac36d2c745eab5994c988729fe4d1162483bb44abdf30821bc5f033424b5ea4b1b90da9a82c2738dda221a36cbe37bfcd9ee8500b7959ce949c0d03c00ca7ca059cf1669809f5a9ed38ef336231dc21c0901cfce583b4ea2b655fec2ffdad216025e7a42924ace8029dba66f6b96494671041eb5f44887cf3178560d89c036e7ce94abbb732938837d79a6684bd0b59aa5f427870d4e8c0c85f851c10edc1817e276881fb1f00a9224b36af297bcb7a8a0734a6c761a1637c85eaa320a02c690ff4db434cf01cd1721a3b113a57cdd6ec21487db41fa0437b3b4126700f0791262612dccf6a6d37a8391b6c28f593c286504b787a256c63976746e4f659f478407eb002ac3d16fb0368a13a0b33a796e70eabed0ac4ad99d50329c99598f59d95c552796e922e18656263dab6b1b5f95e5a7488272b9650722c5d5d65bc242b2deeeb5b487e6f70e8d4d30430426b4d64468cdee7849453d38171d7c6deaadfab4e566c21f2aa7445e3140e0fab37381e454fdecefc63216aa1475567edfbcf77e597d9a693b8939ab532d91eab567ddacd71d57ad1cae6dc7ca13f440ceb499a0abaadbed4a177c295ba9296a4bf9f828461c033c7889bf952e05b1c8f98e953b193a46237b5db00c3372d4953fc80da090544d641fa3ab7ca8fb07f26e444a8a0cf68239722b3731a4462cf96c56a2d28b2a44285c04bc9a309ba583cee776c6195e0724a140aadf3e1d4e80496e2e2abb9ae980f3d541b41c974e1d90234a8f5306369cb0ab932593c278297ae025ce40ffd76f192448185be1cac4c942016b080b56d47ef6c80d880ef9035617406b27a53ff67186a153a69f0794198c28ed203aa7e81c672f52df71766061482d168f1e78a8b4ab82ac7fc4f9cb747217920833314bde06eb076dbafdd28da01e9ac48532abb5d4383dfca85bf94927802891a01aaa1a3d4df9457bbc4d5b53bd75c2e65483b4c5aef3adfe7d2b5291ba9d2465c9e362273b623bb69e01aacf4dedc329188d4b2118585c868d2d56a5d7c32556b9619c88e184eb0a3c06dcbc56415adf0f0fc9fc144824a94ac1bd74945798739009b01bc12dd0db9e98a3125c21e73d77f3e311996d52c89abff1b0f878476e8ab6d04e006a272f51f78a06bc6c87dcc23c1813ff9254e8241af1da529148e4d6126abaa0d4c98eb38806dcd6ba9c3bcaef934ca2b61df5f91190382aadefd541592443b1d85b9c6603d4aa3d07b6998136625382732ae988029e20fba41fb6bf25e836b105dca8d8a2ba035a846802bc3e42a03d248bde08ec40faa8150cad4dbaf67e92e5731cc221e8efc6b30b602c504bbea49c122ca6928646ea91a82cba53863400f20aa14c3284579a33bc95cc222361905a27a0866b07627e439a423ff657ebe4e06f93f1b4ec0560ea2d4933cde00e0a32195c998aea8471b8b91bbd6f1f6b2087d1e513b4d04aac46fbc1e66f1a4bc151dc4b9451b63cde107b8bf5be95e5218c92d243692b21c2aaa25e49db06cca0ede0d310f39c88e91b3fb52e2bd74fa442090f179b48c4b6385fb77e4f2ae08e8811ecf6bb53ac64566fb15cf50e9550b53379b78bf8ed96a4a6633742b0908f1b03cd538a191c0acb457eb68ff6c84214d88f5517d46ce0061b42e72eef8b140639d8b1f232c904ecb3f68fe6e5c97b21be24c27922d1413697f9985e03d042e5eef0457462eb0482c0910cf2aa53c581165fb0ddb6e80c0da6c021d487c91471d658a50742b3d71822ef136bde010c99c5f96101d6ef7b36f77c572774f80fb18201592deddf51cef30294059562a7b706101677234bbfde48a0b620a300a6b5bcfa7ad01af9896d00e11a80003f0f34565e0aeac028572dc0493f2eeac849f0a0b0363be88969f6005c563a0319421631e6ac2880de8c804ad36b370bddeffddded783da522b6bd8507af8ada39b530932e191048012e92c5bde3259c13db808f96b9e3cbd8aedf8159eb56a0e453a36679380fdbc8e7c190bfecdac6234664c23851f73cf5154ffc0e13f658bd73101e2606343b1f1c1339a0b9196afdec032bc397c4a9c43dc867c0e4ec9a7610b7172ce0e3ea60006ee903a00ee0e17bac9f7f7e811be9c267c053b75613a19f45f4bc9855d8724bfc62f91d152e76282c06f452cb156584ea69ad84170dfeeb86736ae668a5012dcd6711f6a020cbe21d4c7313d69ae9d77a8436d48bd98e1c17b38e1ec2767947319ffca49d6a726595843c2bfa2dc41d2ec8809c2183a21fd2315e8aab593a5e43cf683e2d103f9f14fa85b1f76fd34fa0dc91d2d1261ead53886d92579f19840cad245b3ee544b679f3970e9b737ca3bd1efd9d3264e8c51894fe52e036c71a796db09607ada77b7ee7be0929928bbfd43db0252a5114bb1c7c69cb7a26caa524f748ca505c68611fdc6263f1c2c0b8abd03c773962d4259e44f44a73803b22af902801c491058bdc08ba6058d86cd5ab6a43019fa8a993b7eda4d27abba1864c80250a2c2fc417e6a9f8ab287a888b74645f5769652e54916d4c06497843a89ef278ce3bcb067886870523fc16e446dd08e88b9a2c3b75f6012c824bbccc0d3f455dd0669077d120aa6b32a6ca92870cf787fc148f47b6e0c012e7158589122d4c1a909a31d748b66974ae15a549bc475f5929affca2c78d3f1901cc1694988cd88fde60317b3dbe821177f1a82bfe55d1580a8393ffedaca9c16a830eb3cad03a091f9d4190815a0e2d58f563eb5cb5abdb049c3f7540dccc96baf146766e88cea9f375db3503ec5cb210c03d1b3ea81eba9c7725f4a153034eff01a0011ade154d8c0982250398e50d8cd44576c3e2a912bd3393579693e4a5fa5f3428e1684fa12c5f0575dcc119a52c59ab543f96b8257ad9a86c8cac02e84936604edb7177eba839dae26c578a6d3b68bd84b893a28bad62cfad03a27851c97fdc170410e41e8025aceda43a4c3f06a3a3564ad0f9dae6297c1e47b61d2d82dbcda8440bafde706df8c37c72dfeed7a2f8511fcad9ad02e6ba3e8a1c1cb3e5276cc4cf2f4411c7a2da547db0a02aa44b627d7a4fd6c4bca41a49b4eacae55e9882329793444274fe906a085246ceae7ea10b7619b117234fc229b6da812ce02e77dd852daeb42de2e09fee81d0f755171b11441f17c6e234853ae3b53e2708801ced91babb42a4e3e1828bfc57797342641edd5512fc8c07ad28f4424913967e8bd1a1eb877c09717b6c671356a6be8cd2fd93f7d3a6527e796981acf444727f2628530ad59af6e07067d43e95f4e8a1fd7a58ca72f62c9deac20ad6d2b0c883f49314d6a1dbb12bb18ef41a02025f4511326ca884ce6176e9306bb3f3395d93c9e22c1160b81cae6e279b6e3f9a4d15de0ba06fddf216c1a57bb5300c4f6e869f3dbb0b6d8a1b061523b601fd67ded53c524aa7326487c69ca2ce157c262171147e990fcec4836fc606ba558a6f1979bc6990528a181205b6dfcb4b516140fdce75a8c8d7d241f59501d3800939f570ff9f8e06cfe74f274c4d57ef05989c2aabf1e9731c82efe94edf9c6f9cd2b9b3ecd25c486f6350e6eda7e8eba3f7f2a35443834085b52a8657186dd93a839ad79694db21af9c925a3e9a387194d8dee9c5106dfa382c26ea85f6769bf5dea3377d2ab4a4506fb90fca720b7fae245693863b97c1528a50eaad3a90dd42e2adbac440c0a0c4017b96a215455d2689e9c3e1c225e9227f330e328d1d546c2f6217a22fa6535d6308bbbf295514f5e21574b45def480f2b80bedaf9280efd387c60de41c5aab527b105658f20c1a822d087d11743a142208b73caa8a059af2820d29413f603d8e3e87c9ab4a0d01bd062e57141cdd9ad53b9a80ce92745857c88e8a01f5e48d1534cf7c8c24b01e9d51f96097ae96e0580563fe4977736500a4a25e87b8ca61f5db4cb192c97e6ebd6b24e2ac9872f4f175138fd4381f3e44753c111446fec6e85e6890f08d71becefd5a80252320285a0f14842c4f307b5e70d0b6f361f341aa5f9620c8a300a3f53d541c400142a3b2dc2e948737467cfd022ed89ed4b7f17620a1a3c1d62ac66598e529b4c7257116048cfcc1b56976405cd90e053da6a2ff3128ac232437c9a5f1197e0565167031fd839d4c97e007fe06c26eec56ec30b1612cc64c6641d82357aa6835a50e4dce672f1973c874e78bc3512ef41f85471e49063270fba81988f55f396d3939e8ddf0b816cc1b292bcea155be9861682715a47f42b814c68e3b6f74b780fa4606e04e6757ceda12e6f3b5616a515caf4bbd66a704a2268af96a296ab3169a147fb9b6ae28170cd2edc22b123e1806833590b8dc6c14bdd8de87104b997686fdd4958afb511fefabb9164821c744bcdd67200dda7da994e89e5926bc82e57770e77cea75642f77084a4684ef3064a67d2cce1415f9c3c742a9966f209d78050a392bbab729ea6b003436a0856a4bc246fa596992ff7c602a479b97aaaae8279bc5b73634465bbb557e91a0278c594967d81e910dadfd6024f5de9e37399a7441345d7120901ed9e8b91d3078bb278a39de6f9bd97a0d7df54a665acd8a0aab7492eb01f2c7abb3ed95b37a9bf9ddfe62466c34cb99f1a04d7b8512048a6c429bfc492e651261ac6eb855542345bbcdcce210b584a191ddc2a88310bc8b0694b5a2de76da7d6215ffbbefc956bbea5a525654d7e34dc4a58282716b16f8f05399417c159d9cb5419f1932837783b1a69b851776443947ec907486ac824613d8d486dddf3d86406e9368ee9147a3edd4f69ce8958b5582bb6319775e184bea554f34241f8bead9240255339e7db451dd2e7f19b127b0b0fb3efa1ee767193a2f7edb8f9542e4ede603668060a8a64b80cc275709e5b01ca382e83b4c6b09be8782c627ee81ca6677daba5d075483aad12ac36efeaa29c8c7a491401219bb124a3d3e629b639a2a430d0104319a8f851a4cb03013664b9f0730e3f7f9fee211761ba676486c9faefdbbb6e8ec42ea48215451f3bb95131626f3994254184fbf2973b284a4b6067eaf5b9797c1c14d86389ec7bbd69b8641e47dcbfcc24fcdd6e57959fe2fa06139045b5fc8d4d5dd89aa0ed9f07096801266348c9f6416635911dc5075aee731de697290e798cb0cd8d7289418dcc7e9e84cd354badd2b41fd3629845e18a692fc4874430090bcc44eb550ca56ef8093bc2f3eb2d02ae99ebe5c9d8aa9a7804f9162a41443e163f2b9ddc0ba48fbae6d68d7152c95872397a9e120749f0ea2531f8174a099f18ef01676c0430a1156e20f3b4497bf482b3cc9d9217f047f00ceaa11b85b23194c00abd08f5d3113b328f0b25ecf627f6299fa8836375b3ecab33786941c98d0dd5b34abddbda32e046031d2a539855ccdf53f047ae0c8e8705072f61efe0bda55ce007eb9b6784003a7aa443e06ad66fefd71e7dcd8b615f59a1101ac3b6cfa5b0d56b3c896fd4b09759eb2a715d6f473a6078a63dec5599295972e47547f49477356c84b03b806209718912ecf461e71df3298e190c439ecb0a34a45269a487833bf49fabc51af90e1761aafa2b19ee87560ad0ab7ec1d37ccbda06d782b6d9bda028d580bd523e58e12a954bf74a06a81bfa150a129dca11a25287c892c2df9680faf46acfdd563ccd3c79cb7c223074c4ab7b115886bebbb42bc7227d150bdb2ea7ca59a74b3a3fe527a44c441080723839853a3655b41500423e195e99af62b799d33b7c4e79f528ea0eee7b0baeae27fce3cd2629a5d016b210f432ea66219d354e55d01674a6e36d3786eccdf6e51c7ce581d5fdf915bfbd05d11ea243d10759c120da06a625e5150a6d33c2ae042bcac8e58a5fb678d8498d8cfb66a7d34e0d77bdaf2261b7ae63ce69ab47e569041b2924a3a865bbe2ab7a56da423ed2dac92f698fe328ea6f733f1ab29a585dfbd965ac21c9be812e4e49b06c757dcbdeb76e2bc4b2e2e0b1be4d3efca458f47c273d8f4eb00fef5b9e288ec33c441cc8a3492de90e65dd678a9c0b65ac2235f496b86872fe03bce2601460c90a23643613490776cab41426206a38d22d83376c4228ce532df3f5ab8eab0aca908f9ec62c90ad8ba341eede3e4c7b13270161a552d2a7ed289dc6c121cedd36f1fdfbdf1f50f07344995d00e52c06aac7474ce440703c2abc12a02d7a15aee81d15ef94c275f301d938709ce2a91eef7a06589c1df2b6b6f8d08e74eb94cfe0c091c5348762eab53e52b7d334713bf5c4a080661e704327528ddb5dfc70a4385eeda922b30eca6599d122a446534836d06df5e880dfa2987b1b94b4cc80ead6b4108e376099adb5c0605fc5444cc2f014dfc9e613282ab1940a215e3b8055763596aaed77f52281b9f9faa687b89307a6cc178b064918251fb7c799d5e3f6f4b17050064545ec9be777e057315fc09275db6b0364d1be17173a1dc7f246449d05c8f1ab59d4a9b9158e5ceed96623e890081895322f5fb711c2e9f8a247c9814607259c8683a5aa74f0989c587795c9912b5c45aef7df6397d4b0b101f799f469a200532bd1760a41187611d69fd8c8c7b202ca5e1a24d5cba07e3a28df60bf94d37b5fbf131bf0f4ddf277d571198a065b0051333047bdbc8f2c52058f189234b987dfb4dadbdb72473ecce83b500543e57fdb58e061221914bb540739142f6e01aa50a713327ab22ab77077a9dc19356fc68348a7de7112a7df9ab99c21eef49455169b8c5c3fb15580a166e99e4e8bfbaccc3f8db684bf4f49d7cc2033626b47406bda3d2d1cf3f8b9d4f10e1b5becb16e1fd9044a53f46b1e2c3df33e74fa9174640edf62d4fa03670769f81ea772f54c5ab3a79caac61c08e51aafe80d0c15b40128aa4af96dc95410d01614cdc3a90687f58beed98e7ec2449c57c2e5195bf8e8fe49fde8d8f211f49f594707ee429f73fbd6a0677f83f29de2e5d54c21765786ba4861cefd34d10431d762b200ad0bbbdd2124e9f378eb5b4c63be530abd025aa6b54a3db8fe3994143083e8595ec996b54b45016c0b370ca0b83755bbf488a1140a55dec60099c9c6fdf60a8e50381854ee9b4bfbb4a27807555f820f196d95149b1f4c4b01787bc983d5da210bb9eb9f8493f0ee2467ea5d5bc75b70e2d31ac9ed8159fc4a0ed51ae793c119439dc7e67257b7475f82260281cf981ad78168da947ca6171efd35ff6862bd340a8a995756e9937fe519083b404a3050aef03cb935861e68bfafae0ea17b566f3aa4b79f6a10d7400b35a85489d90eed613013c9f40dc5376c5f61be8a3b5562951744d690edbb286a4fa96c3f7a3fb65fb2408c8897a53be0c67362ca95e13e227d8be17c113b6603cbdf3eba47298083ed033f08e6c91bfc59868f5ad92d816200da1f2c7eeaccf8cfd7454af4231eb1a527b5028eb00eb785b1dff6a2bed52f6f5e09229e671b38ea6f604cc0991a7096eb5060594db3c9b3db14cd73313ac63e5ff38a5a989d35799e5b40b80ec72c9f7095dfd334b09b2033beb315ff19de57bcaf3cbfe3150fa1acda52a4b29d33f22e6c0e8ecc6526df41477ac4a156a9d06dd36d3d0070278e08744683f9ff6daf3c82e4e01bbcb6fbf37c277ccb1fcb770ce349f5f7d4a06ef3d6c294a71222b41dfd46cee399d556f2e5bfab3d3d3cf4e99c9349ff42a786ced71b6f231c47fdbe9f5191dea13157bf79fa4dcab65aa4ecdea7a3dbe9b51662df163abca3de6753b39779443568ce9717a7317f12ccd5d128a738ec50a5db3ab0af4be3c8ca2635d555d743cb987a0f0ad14f522efe486996a5287b8bb8b740586b9c81cba011a6036edcac0e6512a2738e76b36fc56c20cc7f01b7a888ecab725a72f36c4e5ca928bb3549359cb9a33ac4752627f7d0a81f4d34b6c1f6f2cd95cea094971c8fc6c31de2f453f6472ab07fff80664ac1ced513548f36acdc3a9fc529d5a63ee99677144c0d6de8747c95d5f0402987d35393609fb46514fbc38d4503c388c3a9ba0dcd96d35ca12d7d9aa2b8ca2940968ff51c677207550608c7e4c35ce5fdce54c8ad862effc60b60652f46805d4b57c27085d18fc68b71d79012458401ad2be5fb2992073ad3b7e0fa304b87f708953abaaba7bacd6ebde0745ecbdb504e7c080dd6c8df1a9b98d3a9a2bde44de8915fae353b6d9e11b9db3815fe79e746903cf75e90c29900dab8ecba7f17c3fd8aca57537e10cefce17091bfae4f7b64c00b8ae3ed923b416d162af0e36fc4d5190c9a35fdc37adfd77fc8a9d917d754d6585d0ce1cd89a76fdd1617dd65f2811aeae5a3a85a8aa1ae855d144ff7ac45470e0a3a7ddc801b6fc21bd5a557e57035ca746d2727650822c8df1cc0f08c67c26b346fced3a0404a60bd6372666ff9ea0fb1f03491db73d9ebb667b6eedf46bcc9acbce1a048b767969bbc1161eb7d073e82a14acfc8e27527d978db75e2342286994aead5961688b9b8929685190580363871e2d320af383d35c4f9e2d8331f10c3802c3de9273c9cb0ec8922c64c64326bbdcfc8ae4f7fde67480c9b087f2900cbc99b8ec226f638343d629670608b3799f2f836ef9bcc3328465ba73844dbd5e8a37f7b311dd6a8ede931dbb7c1431a8e7f30940f490eefdd8515d63b76a7e09188c57f7168597a139f7eb2a2674a958c2a44913a73a1a152b52cb9aa1f4e35dfbd3800cb327fb28f5b3c991a3400c12cd52804c32818421f411d0b119b8fd7d6f81286e790d097938f43186266c24197971064df9c93708faed5d9fbc2e1b78f78ce1bb44f1fd7a6ee8c378f605cb432839c07abe3a7b8711b25427d578027767da67c04cb6ceeb1af10abc09d84ced783467ca63003477d2f0bb1e2a4776a90a3c8e98410670ae10fe67d34a3e45c52041d221ac1c8e917be72058ebbdc8f00f368ac249c47e92a9791caa82f98371794298ecd282f69724f467f8e349f13e36efb7e5378ca40ccec165bb65bd124df20b0629c968b2051b3f116585563a36490de6399f162d927b63743039ad0ec5dc5d4b73f2d21148cdd8ad8f9c01929db8fdb7bfc9744e4e44f83f17a4712c983697e688e7e25341d79cebc1cd4aa0299de9a7ec51894f94c47fd64c667c2d4e1345f9168f4ecedbda94bccbff43a005c7d427825ef68382865bddcd4b9008cd80b3fe450e23bded45e8c93fb9fa93cace583b44022b9255cd7209fec316191469e1ad45a2544be42c1687ccd0adeac938ccb0d8d68627e90e98a6a2b1500e92b02844d83549384c62b840b631826f31fb35af65e7eb36f2db004a33a3765bdf573cd9ca883843d5ba6b35ab3187e9c2ffd00e42b4cd2587a8d7e35b3a8a946a0e224bcd37afdfaed986c60c604c7745a1aab1b04870f086ed147c7eecec7d93c43226346bf4341e415eb17ecef495cc0f145eb840fdc7aa9f95cce29abd77327cadbd544a2c11e9f44e18082542ca65236a11fd277bacef254dfceaa6188238904cb75d19d7d05e7a196f1fa3c6acf1cdcb0737f00a24f428fb3a8f14d1c6e5eee89ea0f29d33568155f9d41a3bf04d46d9af53e93e110ca532626cb57751f5a7f9f126858bb1f655e5ca11f1977ba36fe298f4a21f5fe0478a2575510b0fb9c2a7756edf66900a616f12569d56c712e9395290c492c94f43b834ecc44b9535616e75f469608facc4378402904681ce8e19517fb1053a4e49dc894bca0a97fae774d9c5c525f015a6954fb01bda4b1ac9a988e794047d7720b439e2321cda583b7fc2221766596fc5e7de4c254372246142e666416a8d90a960998b494cb758daf1e0569b8b7d6791d661cf972c7ccad7cc324f9dce1617e5ddd46a41c144d9c318359ce61cd991fe1b4e3196002cadb6ded05a23f7a2dcbb210572e616109b339ba7ae7e9cdd3d8af31c482ff672c58747d17efb0f37fb00d2baffd15ba6b48472d1aa20ecd7f9a6cd4e41706c7797bcc52070367f08e8797c19423f57e733a1c293104f87166ffe018533635cba3f4ecf939ca318389a410c57a705f436db2ae36815ee73bd4f088977dd3dabe001fc1aeeadc2297d008576241cb993ee3a568e660f59aa795873bb90af2c9a1c06261819ce75171410be73173aa83734865917d5c27cbc9e59e8ba716cba4d90783231bd032c26ddb7f42c9b76ec52dd7e30b7b72e2651ca5ce230244b16c95d38b35ebeba9e10d3a49c653c992ca06a5f23c4e7f46cc848db902adc8ab816d62126030dd27e1517cc58957ece7ffad27efa364c4bd5c61b5766589ae21151b52bb79a76f0433eab5d8c6be9ed64dae3d980d56e6e12a64e5e2977339fddca5f607c942ac964abab5cdcfaf0999af5f7db504d10403e92aa772a533acb10a4c2c4c8ab097b2676bae583ffca6aacf447b3179ebb2c12c86a437088a625549389009a6a00c56f00031e5b46cf162cc884f39b1a3c0c99cbe4c740b3b71ae15e98f331b9ab2131259cfcc812555897ad6cc0179e69d3caf6ba55d34baefa8c4c61143e62638af43850a14393da343c0f80c5aad914d4e96fce5e22adbfe9e543226f69287cd21bbed2579df00a56d2d312be39474b5eca808efb2d93cde4a837412aa5cee10ba8db183a9e3d012b2be67d44e74d09ddf31f06df1a43c7a78b918ee7d35fe96913bae858d7b9424f8d07432741c5b51ea98ed19d3996b7b27af7db4b45ec83be7ba808ef3313e5bf5a2ea920080581cd4be483feca9922abffcf2084108acb36a672856fe51158fcdce00f6fe4b107896da1dd9b2a2e6ad313d6a93a0a4c17f35940fb18a1e8fc97c21189ff9d7b3e723e1315966a7f2c98090fca8716a731611d6bfaad42f0148671d1187943d24ec8992ca236de82adf41365ddb957ecfa0c923bf10baf68754cd3bc73071af81f1775024c4fee15f0cc5d0dbaa9128c9c5b13aa32f4f43cfadc45de4bae85ed0f32ac64e0d7f888d6a6b55df039389ac97142d9bc361217b957419ecbd3f1a43a5e1c2a6b17398405362ce19c9024f0dd0a0590ed154bde43acb5162d787dd32c3dfe757beccf3fb87a886dd370aa62c8d6c9445af2f376462c969fc8e2b75cf4cd6817bf6b44a80e014ab3c912698f9fe7e863ade435e1e3420f8f12d27bfa3765ee848164e61862d44de59efc53f77176760ac79e07e668c146fe5f89c2de8cb76fb74179e9e3f8e63098676bdd5d7d04d3859c10e5c7f8085031f135f4f644beb6679216ca468fd1da416e4397fadc4e6d025fc2ea6a91e26640e1adcf368e0bd74420e5c3a9fb3e4e3feaa873b30f6d6433da895d924bb8f369253d453dd0b8cddf61f1dfeb6b5c3ecf4d3f7f188cfe2b7bf9dde77363254ca486a0a9d22ede8540554cb3953bc9dbd9c53fc0be7e304e23fb2fef369408beda3e4b702c7e3971ad565f8fd27bb53a8e2ddb57768df41646a0c385eee36e562e0fbd343bda4343f25a23377ee0e4526253af14bb05cd28561d7f475171a391e40aeff6637f1db3e588f55f7de7a9bf99923b0ee4a3ab5c58825125ff62e44f25e3823ade3aaaaaa873a6d96a20afbdfba444310ce617efb74abbdbff181c3facafbebc3b6ff5613f5266890f608a18effc2a4fb7b94f6fdbd5ad1eba20e8fa46a3c8eb8858682bc21ba26ef1ca37cfbdbc03e622c9cd7bf7aecd9df2b33a71c9cbe0323f311f1b8c4cf752e682862a134042237cec50ebea41c3b035860e2783856001c430a32b3974fcc399bd06f35faf6dc78dfb90e4e54884bfab47caf2aaeca7b6629f0d4b9fe6e225c61ba809acc66f7d78a1679ead1f29d011593e4cd311161fc97fff7ff017f28183e91740000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/stress/32kb-08 b/cmd/precise-code-intel-api-server/testdata/filters/stress/32kb-08 new file mode 100644 index 00000000000..4a7f681d527 --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/stress/32kb-08 @@ -0,0 +1 @@ +1f8b0800000000000013755849ae25c70dbc4bafeb034ce6ec0318be83a085d41060c3506b21f54af0dd15413287fa9021e8f77baf72e0108c20ebcf2fdfbefffaaf9f7efff73fbf7ffbfac77f7efbf6fb977f8ce7cbcfdfbffef7973ff0f907adeda9293f35b7d16596f2b4da441e79b48d926be1732d3ac6935aefbd747db2f63604df1feee6da56b1ffc9b9d652b23e49b13a174dbdf3133eb79c0a8e18798c26b6378ff20cd1917802be4ee5bff8cbc3b508eef94852248deecfb46982791ff8dbcbc815fb7935ae2baa38eb51993d55e58a842d53ed689526a526ac4ed2732f75e6e391280f693d09ec82eb53611c3e9887cf15055bcced696879dee1a1f9a368af6a0fc403c5dbed7cdbc77b1517655c25d759f52969d6ace35931a131537be6ee326adfc68e871723fa3997b20c6885c1e4c22161f528b5a452991e4b6aa2c3cb6284567987e25a5c360b0cb240462822c8bce79863b1292ac8b69d939b64958837dcc259254b7b46da3e9adf65b4ceb8db41c483963ca5449496dd7c8478343bc6a30b8f01243e9fc4e24aec36ee4a19f6aac1d57d0560361c65ff879b3b018573cb2422539f881cd1b3206bdb27f63fadb99bef14477d2478db98c0709ad6ac4fe67e20b5c02643aae2cf6c1bb5bc158f5bc0c66233f6092be3adbc36b0a218d100c2f1700586394122e6db50e139f83a053f252f15b3f17309218659e7e5912544c39c5db5c74c841018935609f29a6ca55c69553704ff7bf8c52c1b6635c18fc367b604eb4243f8f68ae53a501b805180b93bf1bc07060087cb3cf291787c0913fb8706bc4a5c9354bf7a5733af3603517852d3a42f66b29d66366e736a97a235070a17a3c0888e98a50613e8637fa5cf565511673a1ed76a67d90059a5bc8865c3f1debf82605e798d6bd2c95b339803c666986406e2693f89d89bcc9b341ba374407d87d24a74e76a0ee600ec724aa445400ba961972209b3695fa9aa451af5a1b69a36b8c0012cd24844a67c8c08f78ede3a3d283324a0d517c2e562a36d54d3998284abcc59a6a566ac1a249e5cd4582f2957053f91019c939ce28281caa5598852051118e4567e4cbf2694cf20437356ad953bd8a88c36376bafc25cc133c3bb940379f338cfcc5adafe39a627b695bb1252886c43559bf87ea28905fd05dc1755de845636875c8f61f84bbefcd152c2372401f23cab53af97c2d0849858c48c12faaccdcfbd6836ea9b97e036479bd50172ec5fec4fd4cc801c3f9bdc8dd4e8da2ebd555472419800b3aa007a8caac5297a100e2e4ca43b646683c2c84ec56006a6acbd9473a283c3a889fcf940b39d11976f0438804f4c11d70e915085e4c232ba13cc622af10c7dcacec5a0bcd99919d29546745919b2e332578237b7221c218f26c00f67a0edbc31071308f99d85315b96bcf5cf22cce41d793ddc5452d24b23ac3218b9d908440d6752976a542c66838718b7e16431e178739bd797b7011fd76517ee9728661866713432c69fbcc47fad58590eb6a63558ef218db06ca9606ae17c97914ea7e56ecf8d89dbd2d1aa788be7bff6680cac29f2bae461c3e2c7b01fea823648460eaee8d5eb5695717c905b1433626e7df3ca079e024c46ccb7186f34b109940620582776755a0cad4e396b4f8659ed14b41daed54ee2c9ccc3c83de59cea25c821a25761476b51023e6d8e46beb496e8b46da8eeadcfc8b5beaa3bbe4517b9f4daa8ccf13fae9f5d2dd8dc8fe7b460602598ca9e31198954a81335139e2d96d78d1fd6fcd01df90bcce59123f9d4543a461fe99c46dafb665b87ff110f20432bc93150971af7795f6ece4477e1f860332e7ed988ba0a9eb6ada19e577316d285f627f99cc076c60a8e74b9ba0a6e887edd42182d9d1bc9de31b4a0dfd0e3229455d1968d0b5a0c03126d0a6631d367db0b9e43c0d52610343f971e9a06a025c16f6b0ab15faf02bf7aad53592a66596debc0483c49a48cb4753b235ed39b71acecb5e784bc23e79fdba615e3b106d5c8eb9954d7a4e20188c1435ec0f5823665b1d1f0668cce1b8c3808b6285c6399d42eb9ade006b3e09e4c924f7d1c93bcb0470c5833f50afba2a2769d0b1475b6c5d5798e30b4dd75e8e2dbca5d9a1184ca4b4ad67bf18e48d56191c5a43a7a6e1b676bad782e101f96ca1e5c720d9e59f21b604393cce1ed2d717f2336abbb8a4adcd8726e3d0ac2864bdf5030ee2a6bca5e4eda1dd3daff43fb1f57b5bcba20c67637cc98e101a65d9d65ba9dea4ce1c7c31364a0f448e2a9f95b14484d4cd96e08d115e7bbb9dcca20ffafe34ff968f48edf1db6edaf27ecd3eb89fcaab5bdb648873fabc71873bd17f0212180165d11b42cf7e3a55a86ee9a8a5c7f605ba3482d2d8193bbb5bd5af24540e447d04bbd636a08c8d6f10cb5b20c34b118ade6d0cac5e6332ece88ff2079eca695f0b7a74676a5cf71680fdb8f16ab64a3e89500874a04db3500db08cd60a1a37fabc836944644295b9334dee3dfaaf7ad839752007d92e61e95364acd0c7b5571f705632bafb53f54a6800975c94ad3e6f2e9f39611a915875fb4db84782b02eac8f5c502d8332b39990e60566f65be5a920f0403dd33a6f11179914f9858c4e671b4369c728c281379b287ecc151f4b5cf697635b27f03dfb0826f34b249dc7a4b97fca5598a7752cdfb83353b3846380b2df898e00c8e99818cc938c65b4d7f2d73b7bdfe72ebe8e5624c1f76373ffb2c6904bd589e095823c80668406d4699eee9618322eafec7fffd05e9125d86bd150000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/stress/32kb-16 b/cmd/precise-code-intel-api-server/testdata/filters/stress/32kb-16 new file mode 100644 index 00000000000..1d74ebb5488 --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/stress/32kb-16 @@ -0,0 +1 @@ +1f8b08000000000000135d59cbae25b70dfc9759f705284aa2247f80917f08b2488c00318c4c16f6ac82fc7baa8a52771f031ecfdc73ba253e8ac522ef7fbf7dfff1efbffcfdf77ffdfce3fb2f7ffcfa9fefbf7ffba9c4f5ed1f3f7ef9ed9f7fe087bf7a8fabd6706bb35cbdced6fac4475eac8ea87ecdb2fcf298adf686cfbb379ff32a31c668c32f3c3d66bb1cffe449fc6357b15167294d47f7de5ae0095bc327beabdd0307db55d7a865e083a8a55bbb669d338c8f04ccb8a6f96c9367757cb306eeae63d53ef1845db2c2474c6f86bbbf60ee2a38a0f0b198a3583398ed05ef7d7969a34dbcda705bc367b00467f088e6deee07a22ed959baf3b352972f2ff4080fb4881e30ce6daca80197108b0abb0b2ebc5ac177816bd7c4a9b11c8ee0915a0de7237cdd6c2190cd569c68e247066ab402277087825d63b535c685770b1ef30153e06d59ba0afe5ef07f1a035478b44e1873386faf0336c7736ae78bbdcad90c2a2c2cde196d04682ed8dc46995d965d30971185b7fbd80e1378bb790cebb2b7cd3e2d9f4328a2cdd6c72b7e8ee8af62c66820eff489de224db075f4a83a06ce0cc2aaf6e8455991c5caf754d6f02a028d9f116b2569d820861a838b280329887fc37bad2d25a886556f3b7df447218bc4af4293e1c291be86acea653602b255a4b925ac3e53c2c7e12391075f3d3213132e1b9cb6e27812654287e0e1bcc1b35d207c6fbcc16c1cabdaa94b71dd4055c944278a5e4ff37a5613e027f7a7ac8882ef4a41541a4fc8ea52d403b8e0971ba5ac4f1cf551bec3cfa5b60aa23f687aa1c7a82b9d3c6a33eb8357225a842a6a8a5ff835100861170527e71b4c46025ed5d394bb903fe7ca10f09042541f43c21a660869284f01940100b30c0fabaa542758ba4f02f61d9959713899c958b9cc795f48dde3d4387c8317880f1493352017e6138ce008c45de63aaa5ba7df11c487481d892c808f20182a4e2f2c27386e7ef849104826988260743e85fb052f02aa88925e6141912d562601bcd3be5adc488f55602d0eb6ed2e0e29cd26e22723e7ed3efc42d21080bec1329320de9799487ac5cd1a8c791676a3fd9bc271ace33e1f35c644073895b28b8be08f3e88ad06c62e9d054f93010de559b48f0cb09a407ba52ce347ed2e8274c182440d94d7f614d79cc7465eb3ace3e586082f8482463878de0ec3913cc9549d35ca0aa44b88b6e3c8998c9ae4a656018f11fc8124b8ca01e17c11946cc07d48b32eaf80f720eae0ea52cebcc176b6a71727012428c0ea1f8dc2de5471b0a18c4ef2231b62f1b5e629902ef4016a60c86c967ccad249530f9ea44d3e1d28171b76650b6b1db9469a262bb3ac089c3d6db1a510e80315d9b2531e73f2c620695da2350669cd6a827f5d0841880d087fbacb068a029a0b6143b55462a6a07975f6b281bf33fe6aba3d362fb279d4b63e883cb2680bf2531b5f227ffd99224071707eeef4e30b539f135e6307313230bbc5b3ee37acd46417d1018e5b5d8daf8cde9cdd166ac455cc06cc141934d8de704f07ddaf313771c3060252cd598c166cf5fc3b2819d07c16c22b18a3cc6a43db94739dc402a31670b58076a8242ba40b5034640d588fa1abb46b2aa84c497e1f4090ab2fdac2d5618004ba272b514a01d96782e1c9fd6e598b68cf3243f1a95b306ef03414c064c7a34418b1cd5a03fecaea84e6a2816ca62cf98ca428805f8ae3104bd4047b3cb90c55301a5f8a4f6e21ab80fc08b724ef41fe50e5799ecc7a7a58a4beb5e3c3e649f64c142d9676425cacd64258e6db433d725f0fd1d84787531047ec6388712707f9912274afca9209805b13f0051536399fa85800c35f1d96773cf40f13211b84aa46c8daf1b46fd1164bea86acb5e5519fcc93bdf4c8dd5ac9f3ca6a5190aaa046ee6fcfd340e76edcbb1de3bf2a854cf58caa807c4bfc041fdc7e666f41a5a869a2578afe2061daa23ffeb44b9063265b0d2266e9ac960befa1648f9fece1d2e414e3eb101c1e240ad02050ff146badd9652fed8fce64523b1273ad2bc6601b8078c7618a604faf2599f39c641715aec7969b19c1529306db698aa7dcb3152ec4bac4914ee02c685edbf20a4df01e4c369d56047e6d3b2097150e38a1ab2090c80753e3c7d6a254c6b7cce8ecf7d4a16248b4bb2a518d030b4d5f907c7668b419790161aae21fcc2292e2a972e875572701353cfdafab2cf7ff70fdd1051fe0649a57b0fc9c7a9c111a6463b9b97b3b05be8216c1f73925153fd22b871dfb98637c4b5a7e97dc54a5d9d9d4fde9ce4d5184cb03370cd17bc98629c5b0107145b4d723a9251937262523f03500ac943d42a63356f807ee124b82efeede594e13cf5e9bb24be7d27511e6adabc43b906bb0273a9927e3b7b1bbe71d9813596660d4c90679ea8bc359c8b41b64d560bc2637743de47bcb44f628a50d1d5018ee02d8c4d88aee2025b885074d3d5ca073cec929aa380921e1e53dbee0a409fc584d18c8e51c138af860f735b578594cdab7407a1460563bbb4156d00793103cd0c53d950b1ea1b87b110fb8c0f655a8e43898e0d4803968a94ed0fcb3f929e62f69b1af618512c1a9ec66b2d7e652d715d3d5fa997418b926756062038dd57b52caa49a60799fb2c73d843f1a2d4eaa7ee59887a4d04f140785e2ee148c2e45f7edd85b5d9fd0d329682512d5bd5f006aa6e4371c68647e7fc97edc065a5227d03488c9d7e85ee1b44b5c539aa41f0f0f125b2d805c4a075438c2cfa00be5865248533b7beb26d1ad10217c61d361bb969508de84aee7e81223572af75c89c9d357538bd1c79035088449e5a35575f8ed2f12c37754000d9a425d494846c6ed5497a57ca43be9535284c7331aa94b432f7609ff33533c5d7d6bef40a88a860230a1695460e771d6ae1423860c57359df9e9762a893c8156c5f052d2bc00e57833fb0be07c181cdf8051e90ec45c939af873ca3e5eae4e3a72053331a555123da4aae7851a2476af9a676466f0212dd07409ef73e787ba3e134b0e7940556a59ba3c652973c3e2da4a48017802f6e8854e4da5c6a2660c4359d06715464711ff0956ef70f6e830ead5331931f277185189adf89b37938a766895dfca29a227e0a4d4005bd6dd3db0e79a01fa55494baf83d1b8755f1658f3f6963e7e6b29b2948bcca08f57a53218aed15cccd631bb932cf24d86edd03f041ca83bb25b73b938a505d88583438ac4604eddd5efcd0c6749279a6ef659204dfcf3d2ca0978d000aaad5d4f09c7c946db0ed546596fb97a5c102d899593cad1f55ffce6aec3bb25ec81a4d8544bd997cfcd17238ae9a03766ee35d8252b3c9c90d82f5a1ee6edf58a0f7fed3538ea0b5a5a00a148763d10aab92cda68e0a24e9b96182901b8d1b5b32e389ba8bcf2f13b205706477c12169b61bbe75bb1db1b7b0f92e1064c709236d82ea99b1a48e20e8f051995a3159ab406fbc79f7b42ada7bb68d24e30d70b938f251f3b47a272f4efd7e1999af5f6cc16e4a5b985bb261b785bc7de0677134df7923f7a2ec55c78f8e281185ee3c5b387e59e98e162a390653be6749a1ca896851e1064a3fbd9acad711ad08d9b2ff6eb155ac2ec155d154be5c8a2aae02c1a5a756342f2b3dfb8758a50533fd8c89e1d7bca4b6e5f1f91837c40cd3f6d32723a8774cc88aa8fa423088876f6e087a11d147418436847d83807076da95ea34e814aa5ace1cb23b5e464bcd061a97712d9d417fdde2038886eb1dddd6bca64eaa4d1ca4923141950737b363b23721be62d6b0bb4edf3dd89b8226331e4b6d9b4a82a92a676d8f28103e62167389e351aade1b241e1de0b7e4f318b91688eb7404f9d989bd24a91af2490f732ac8704b8d7db0d0e324026692d39d81c1ed3fd4f509ed24e38db523f3dd26d69b579d6abedd26a2954e7089f6f686034d1e2c90a77a6da7fec8962a43e5354f7470f02de88271340278ef92c3ee7f52a3feed4ab3ad356bfe73114536823b424d1cbca47202d29f681996567a9d025a3d1b65857a67d572759eb7710a2a25cef41af75b2792eb3a8bafbd912ce1b9e8a50eebbcf0672c041bac7db7a9d5af49c5d21b9b81d5800aee80f1813a8d0d8163d572cd1ee05dd33903e5d2fa336ab9f0f395e485f818bb8221f7ed48234cd457987b1e96ebf69c65b3c9f79f44372633669b9e223ff72272f6d020235a642331e90d1ee290871a19ecfb2d550b821cd8e6a5a99970de7447cedab49f595aadffa68b252070618f58b145601a38b02e4e4d69e0eb12746fec6a8e9b7448828eeac4fab18fa151a8161499722fd49a612aa7b393b424c8be52c5b9e862b8053c82bd93b13afcd54961d485893d02dcc5f94acdf91219b7ffbdfff01b624769b131d0000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/stress/32kb-24 b/cmd/precise-code-intel-api-server/testdata/filters/stress/32kb-24 new file mode 100644 index 00000000000..c5c34ea6871 --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/stress/32kb-24 @@ -0,0 +1 @@ +1f8b080000000000001375994bae44471144f7e2713fa9be59552c00b107c4002c2410c20c6c8f107be74464dd7e6d24644b7eeebe5d9fccc888c8bcfffee1a75ffff9873ffffcb7dffffad38fbffcfd5f3ffdfcc3efda78fdf0975f7ffcc75f7fe17ffed866bc7a8f56c6aeafd9f71873f3d19ceb943dc778f558bb95fd6aabcc987df15d1b6def578db5d658edc52fd61e3cd05869ce117ca965cbab96357694d2ef3723586f9edab545ed6befb5a2bcfa59bb573e885e83673944adfd343e19ad8fdaca6b97b6c7d68273f77dd67acdd15ad4c6cfbf5aa9bd05276e3a44b064d75fb1db281ceaab96ae3dd7e1ec3df6aa65e4d90a978bcd027570d03eb985b6ac6bb5cdf1fbe4728d783d0f443faf56ce6add3f62cd60bdc2a33c302226a7e1b4eb9c181c21a6e3553918e1096ec767ec7e36118a4354f947473a650c6ed782f55a2148a37056fe7774a23774d6be46dd5a46e1ef8a08e13a4391608dcaa36d71dcf21af58cce6f385e21b1afad4d263bd7d2ee4abbe8d6b108c96c8ac46e959ff4ae1fcfde32d984b43cb1099ee39285dcced52a772a73558567d5ad7cdfb0c5fb2fa55c29d0d908536ebc26077df53aa6023ce270231dad0f5256f8e36c1d9dac8e3d56ff883ba020f59d841b7867106f0244d48ae344aeb9dd9ad1cb340cd65e5a851cc6ac4eacf25dc6e15b8360165da30d9ddaab02cf1afcd8d0002b3cd97465e56ad546d8f76b128ab64f57ca3970b4560c88aa4d33f244bc1ee5b9af1b7152d34e6d952b1054a7896b118bd2cac5d16927a3cae6ecde4e3c0544fd68dfaedb08ecacb5f892efbe0e8570b807611b9dfbef7b140afa742d373eb3c11d3820d1dd73b2566585396aa1a455814fdd0ab2f151049c762acd638611cae2d4a6cb6295ed8365f400b90ecaeff7c303030c9357d0aea04764011fc0c8316a86c9189f6211d75596c35e857865616c514da78e59b666661205543d09052fdeee9098ad080648e65f1196e1d3c8b3eac6f9e0defa1d70d6d5df75ddc2f50973b48fcae35461f08254a801d0eab687242b4ea1857611679034e05742ab404402e26cb0145cd7c549ef9802da2e0621cdba15d021f67d762a056415f25b57dcd8f18b7543c0398e1721dc4380ea0f6735b0c336e5f94d37b0ea310db6236e2d173b4e12f00fe0c2d9b66adb70a1525efa32c120d8107ed1477403808a87d8dac30493ac17953d8cba786a5d4e55361443d525e001ee0f1c5746c3d898aaee3aa42c6bbf79eda822c4d9c2dd8677c00db8224a960978730ab8e59b0f520a1e4e34236ed7dfeec35982007490a86fb98231cd61e2ba26da80c222799012dd91e51693c8100b4a8442da572f1464d59f6216cd62878c1160e1b902677f64dea1c4bb49dfb72cd64276eae3de76eee6bc42dd64bf268a085732f42d0e110477562591c6e90fcc2524037cdef897e1bc6fa1cbf061171d101c26eb8ed4cb61615b02e056494a9510c5e0b6b5891a80368413e51678efbb6e2556922a9c8b2567ebc98c04dd52ccd630406fb912111c40fbff24e80d38e163a3efe440c46d4b314679634bc85e35a012a54a816293b9f3f6e2621d8e00751737e4146515a99ea45378978b58ac3295e013aae85d15ca621a279471b59f3889c8aebe613c04b0da8e1860892ee44a7cb27ec88b56729d05181df2144b3aae82847f84b93ace2051e8c669c6d534b51ac3a671a5ad5b802c4afb9d25fe4bfa24823c2d0efa8823cbb3df8e0949287b4a9788bcda294101a65571a974c022d2811df2153d39958f80f8729ce5d98e343f3f698ee7acfa03bc822d21bdca09b93c9bb4ae869812b1196881f44eb5e02084548bb492222dc06e8515e6dbb789c30791eb5963c77a1287b89cf992ad3b9cdf3008f9287022665c12e6af8b1e5198a209adba2ef98982afa3631fd6f8900be2237b89120e859f47647fbc503dae962c5ae87da9f61d4d32e1b0be0d14c03cc30033e6ae9202b46d6548248b6029dba25f363d8f93b1758457f4d9f5608a0964d3bda9895576837f9f3a52317c964cdb22605dc3823bdb1519fe9413c77b9cb8d0573d095ab291612b932e0ef07f7036dc84c2b0df15219b009267a3372ce6b2ac5d9ee345f991ecd52e23dacc5d7c7e496c842a6c3ab839cb9c039b356f63a7878302241052d782fb98d0b64cba1e4ec80d7daa3ccdb567ba9366cb852744bff723644d92cb7a1686b0f572f867858bab148c1a534645882657b1fcf9e6d8b273c744dd3748e4e464209e8f603943bb548b9d7296c913e708964eddd6893e90a6f295b440f597d7372d01b048d87617dd0d4aaf579b6c14aae0a4ffc01cbda701c2c1e151b014250d1b2c0eb6b8517473c7dbf2d077cc265604be05d808c95b3d876cb31d5115dd7ed3da882572b0b6433d94cb195305e2e0c40003b6d31ca6da811d79c9e1ae05275bf76eb7673aeec7be2abcb0801e544290961a1a4eb33a2e66a6e13f960f94c36003906d3ff8f2fa32a0318b4a0d59efa725cf8bcba952897695ab12f363aa90cf6413ec84ba52390b7baa2b08f217d3ac2d78b3ae2d183fad56f8dc979bb2f854ac317512369dbd3e3d411cbb922e45b0b771e9a9b02d2ccb0e20f635a8080c240d45e2c21f71186a5d90f06d56948107800aed2edaf1086eee04b003c659a2d447e18b704f321ea067988af8acb40f2bfe340662447dbb9692d828a999f07f98075e78b94350c3d05d4207d1dc029e9ded715bd6cbd37b64301dae9de248f33f84a884b3fb2f9af5f4283a3a2dbdc3cf62dc4b9d927899926d3a623aad7c12de9d06f5ecb7ffccc55d03b0cf6de8406031f861459b5cd927f0a3b88352fd7289a16fcb714a8acb6ce28887a7f23a5516d20d6ab1efaf0edc0386afa7ac89cb03c434b0271edd5dee81dd4a9b8c4dfa8d5c1d4e2aeb661eb5d5857eab7d617538e4bc86a6294bf480e52abd5eb32ef9365b502d55888b23a3688a109b0cddc3d39774ea34da3a83c4bee6c004f6aff208d95f5a10f8eaf6a788be255b6a242b2d14cb29064a308c133190dd88b5ff48278a745a7440b12368e98ad5cd5f6b7ca7091ffe32e14df8b6dc275e761a608f66843d6ad53c463d11596fd9c4da8f11ac239ea0d594c1ed2083666944f9ad9b4f9e1d1e61a868257a32d4e57445b0725a81432b356fb76d7b52c1a5113acdcef6c7b122e5c740f17786b16c02777eb72c997857de25e7a62b0cd5a554f52671761a5da90d52d9641939e9fc508a90ddcea657f58656224fe1a828f16a6fcae3868bf047bac2f774db22420726b400e23a82a85279d58f2ebe2a51458a5b6f375b6d2a47dff7ae7837918467325dd4806dc0aa2f0fdc266bc8217837714328ca856da6a417be1206aca53cd41e4f0a74227b42cee7211ba9b21ac88bd325f84ece7e87fa5d783859457918f4b78d328bb22e0550ad2cb780d58248cfe59185b461b6f71888d2e037aa12ea06ad73df56b348e82d01b21275472eeac67a7b8fc0e0b578457649a4ce624a68a70b96de106af314c9cd3ec7b58bd608019272c739da286f680e95f8948b440e92df209abcde90d19ac2f3b5980904d828031fe2dcf90c16a8d6db958eecf07b3c6aa50e9eac4dc55dff2b355ecf40c6368433a8e0c0cf3179d9336e354e33f5837564761572b1da1dd4f2f3d717e1267f6d7f3ba2df54de97eafe847794b46dee672ed50108e26d383d2892f91b8619c8505bf5beddf874a592e5b12dd05c740a252a5f945fcd6d122b37c5f26d706feb08cae66f26336ae81a985997e645b4924efa67ea2b2e59a6dfa8c7a3969a72bf872c90a655c5bd448e5e5a5ae92a2ab947ce0b9191f6a951278313e1e9de1d81f13095293201b13d3d75329f275539f852817a1ca53edf815bcd66d367ec1a1b6649285847ab892a331e02fc7bfc2a455c392be92a197eb7e5245f77d87c9d9527c5a66f75972d1bce99b362db8b3b412b2f6c8bc6ebbe4742bc7a48e1b1f5747be15e16a8b5a74dd12d096143f66f4392477a4ff9d866c6334f94b1d765d7799e90576819db99f5451f91fe0be2b4aa74cd173087e7dd017c477cab13bf792132ce1f41d9a4346b3e87ec729a2aa6a3a9f64b0ee3dbe30fc9a3984b76432e618ecb17ed9cb7c93a327c1763640094e964f22de95686c83c1fdecaae747e5b66de18e842be9a1b136cd6e5adbf78c24953f4dbc9234dbc2696255dad4a869e20cf7ff4ce64e75f9b364389dcd5be5b779b1e6d728c9926923d8b9b983bd688f531b4b1d3d9327f9e26a8e8513a22a54b5a98349751ed231b54c8c9db56bd7ff92e6d75de0278182ba6daaa7ee2f9b1839e6f6020eaebad72d47bbb57cd9d68f3a787bd799e91e6e689ee9255f98265f53ac2af75303e7ea9916aad00a056f373d0a09530b92777a4df9fefb9e88937b5851b43b0872d9fb743f5bb8f668f44b3b6357bdc12d9e7358cba0ccdc88db9fef1122a3e7ac2f418637d3be47a69d00df2b8a63e2de12a39f39151d73b1c7592ef7752455aa1780c37d9057db7186c87b7dc296e79c3f719a3ce9326e24ea845e0584cb58c68206db6e82f3c0a45b8cf542762576277369f31299d168fa2b52a3b603e9204f7727bc143e60e7552dc148119f7e50e72b776cd17261ab52aa2448ca0f6f6318e965d2dd6d1b7d9f64c805888f72e4757d9d447c0e2795f233a84fd9a3844ad0d71192e2e0f42ccaf72649c90ab148f6300d22eef027c873fb2e660d20b91edcd9bed9f6642c3399a24702c97ff174d0e4e255abb92bdd6fa14bcc7a1dd4ad1a0311b467b71b167495feaf98b6debb137b92faf46fb240cb8a67970e1cc8ad2864730d8880c43b682ddb31e0f02b2e3465b34a8dab19f4a597214df2da4ac8d5ee5b59ce208aef9ee6daed77b201c7e358853e7fe1b8fa5a9a66619d97455bf60c26b1cbd39b883db4d582d3a47d3ca97863f4762a13527295012e905814617c7ba9ba05cf755ae65d12ec95f2e3a4dfce79dfa0c1737c1695a91e3e825618c9c5078d88d8f2bd8b2e61719ae8c5adee599a33f8f0a7860b24fdc17289a962c8f61edacea35f7aa6d3f9b4d653d08e30a8fbfc37d798e0d7390ec59cab37ab3757afbfb9b83342747ec31d5f685ee47b962fd870783c4fc589ede72e982ede56d75bc8fc687df0332bff3fbdfce49de20df24bbef94874b72440b3c1ad4dbafa986a1dec1fdd4cb6ab5afe99e9f71ecb09150291d8f1a225f3d657f9e84b60523d0137aa1984decf6dbce919a28242dec8cb5132614f56a92a285ca43198e855f0d87e2894d406e61800f57ae97eb029dfc45f61804afea9d4a33ec1f10d69194ab66f1727564bf8b03936a0a7839e652b2ca33ddf0d04977ec9728d28b0b3574ac356dd5c70bd175ba1ace3ffde7bfc61dcfc35d210000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/stress/32kb-32 b/cmd/precise-code-intel-api-server/testdata/filters/stress/32kb-32 new file mode 100644 index 00000000000..f2e356456f1 --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/stress/32kb-32 @@ -0,0 +1 @@ +1f8b0800000000000013559a4bae2e471184f7e2711fa9de95c502107b400cc04202212e03db23c4def922b2fabfd732c6e7d17f755566646444d6f9ef4fdf7efbf79ffefacb3ffef8dbb79f7ffde77fbefdf2d31f7a7b7efadb6f3fffebefbff2cd9fdb5c4fefab9511f5993dc698c18fe6dca7c41ce399a3cc716a2b4fdb65ae350a3f6bb3d7f6448f58bdc733f6ac2bf8f8ae9d070a2bced522e259bbd6deea7ada8ad1e758e5a9658f58a5b08f5e5a9badacf1f479ea3eb33d9567d6389b5d9dcdea0f2bf6ba7838c6dcb3f14565978dff0d3630176bd7c2776dafc209f862d5c66bbe5a29a7ec3ad845db6df16bbdb196be637286afc9cb17df68df2b762d23f7563acf069faf638f598283d6b5f7e614c4a09cddbc107b1d0ade179fe97bd4a8531f9fd14f594d1fafbd9735a78350e21c3e10ed9456d8f2d7e96784d67c78a473dc3a6ba92d78735b4bd15d67ac53633cbbb43562789fa78c31f408a16965b74701cc0376ded7b40536a03c11a7d1eade9d63f17fd331249a87e8ee27f829296984f429cfa8677482d2eb8cc37a1125cad4c90b615654588025384a0f3ea24845ab7ca46f7d78763ed439c6a88ead63b7266f2362030c9ceecccf5d15b75d3967bc1b5cfe6a8f466878c1e84bb823e7b17c9c9de8ea1500b00a518936b4b90e9c3a41d3f1770b85a33a54bb7b0bc0798dcd69484b0715a1449e51599dd4280d83d0c634ee0ab19eca6cdba1ed1c016d6f32261c1b18652889460bb8505841e83e312ad91342ca101ad91635d3f5e201048fa25649933248545a1c52e2da299c8a6db496c0aaf31854aca854f1cd621dcead8319e3d4617d80cda024588edf908ca5758cb7d38e1055fd6f01627d94787338cedada3d5019592075f4467c7a050100128872aef6008568046bf13a172c076235a2363e39eb43879a41913f3181e0d92c324705f1ec4f0440218b0084eeccefaaa46a1f4e4712c75c43d403be877ecee142ff552da8d0c85d594b2f5d937d955c71289844198a82656084cb28427c21a3e2a8de5fb6215359925bf8d3d2079cc72d24b31b013a141ea50b5ca82d2518e65853af162fc1429c43015d001a74b2795737309a4d8f53127b2ace5f60ff2cc2398f1f580732f0664c28e0db99f2ded62cc510e7e77d066be9c453ccc88997f6a038b02c21574d95667014d0e99711eaa9a272edc6709c8d3df6c5a69fde88745fb714e104d5961885ec090c06dfdc05285491ada3cbf38608d101086c29199dfdb822a14e1f9db2e7a5adbc6070edfbf3dd90acc771db0264929f4f252e56e6128be5f68fea3800254a9a77341d0d7437aa0ca443268bf8b82e6376e866bcf4328ed6824aa87c313f289d3bab93e08d170aec90a2895b603cd0f45ac54b4c45da0504b1aba96616b103cf869857e70b91009b807a0849643f9ac75d7008fe5f507f55ad2553b2c3ae0ae0b7908c9935a81681afc1116c482d0bdc6dedf32130d184e57a68890a18680c010e5071429610c0a92a15c5e0ddde61b6ac75842e802554810c764e236d679bce1adfa83a805fdce6ad8f02a7cdc33a81ced2ba7953fc96fc35e94c87f057839072ad63dc1a638f435d9bd38ada2188a91f643edd5054011c7ad3ea235111c225bc4fc68e3bd76aaa7f65a5b42ccf21d94126016fa8c0d9e824ac40c3ad9c7d8e7996be0ac753a79a34d91051544a2edb75a324d007b78b83cb631eda2540cf974e3d817aeb6ed9d4d6587970776fab89a4e4a61df22d9454b5e3a0a557e3ae0661ab52438f836f2de44c082d626c1f4914212e431a41ffdb45d838fea490c9a69af7b15aa1c1f069e0fda8a840334882fd0935d54268574a12c496b9f4b655713fc4b9cf964ca8d03724b6c543924c267624002a64e86d92625d6249a706d7497b4e0c32a5abc60f49d12bab1a7492c9ea065359ea06da8a726a7664b9457bc8063d741cea156a2350737b3be0e9d628f55725bf787d90528934615d3205fe3cd5baae6d97bb140f1913eb3f47055b3b393efcd3890e8095fa084010962e5b6a5161eaae5f0a0a6c568190de0be1b9a5d21fc4815402b852e7559be383d53212b1a243129d692c3788ea21350a2a0c807c94581107c03b92b7a3f03af37db5f4da303cd19bc488f55d5c9419ea6d190df0c5b6d61322804eb750a341341110ab1d636a4accf28995502ad25f3c4a8eadc1cd313c232efb9a2ad8104966a153fec2de3e2b32d1c522e7ea3a84f219c51c702bd4dd7f5a544e9eb224ba428efcb05da85405dcf4c1759202076290375d8dc82778be75bf9d6cbb11ef86ac3a50469693eb26d11a7db9862639d499f453dae6184a06c485da1ed988c980e0a05a51194a5bd3adca2aa9f0b549aa459e810d18a5c1768e9a3eb49efd0f7e655f63f9e85d3078ba4544557e44a0e05ea59c5d89a72f8cad91be689d4191d673ccbe528d921b74a0dbc986114b8d4abc88667b0de385fd35118e85cb91ba5064d97013a5ca0a55ba4f761475f2fab8a6abd2b624a09a74000bcf6eb64fb108b99e147fd814e51e866027ea8ad2addd8ac96aba66a6b0176a1dd9ebd831a6c4c52b1bd6d4ea2c4549d47e794b6a1de9d7d55cd5f89262675a09b09c3fc60cec0f3ec56c6bd373cdaf7d64db0b505d8ec0cee9d911f1e4f1658c74e38cf8d0639a700d08a5a688e41477a42a9ab246ec7095342f9d1622cc52a1e9b328b761f3b141bfb844bdb2486949b427cecb39564f9cf7c827a412eb74b1ab6cba75a794ea9628550f1cae28fa3c8e4c19a7e117c51a96815b086db30f3b2223f56b3a479a2f1894c034d778d0cfc12d9c2bc6149d35fb2e98b6498d013599dc2eb56457ec52355b8a5333bbd406cdcc345ba735db2d28b9087a88a029f8aa5f2934538c18912cd52caea65a6b9ab9ae1a57d1251ea634c950ea791902541cceeec08e183577e296cffb4402b80708e51ea8a54262278682de471f0829794c0aa86d2123d9760a13124a6e64c4f2e80dd24142b9bc8b4953ef444fb935558901b641a414794a0f2a110e78469df70a190b340e2011879295171b6fb170c4a3def23af87dfdef91e402e6211e93f7b439b2ab44544c52d1e8e77364dc80705c6344c922158821e486147e4b4a5d799b304eb8d8dccfe179610d0ba108aab0735aa0e5fb9104d0bea4b9ec13f4fa6ef1bee35c97a22e5b7a6acfb1a56b0e7e4fcc5844ec3a46e401458507c0b850e5547e583da72335cd2e3cb167b63012e7b4399a364f683749b4bad52cec89c853c93e379b3c715c6e4c6bc98ae60458a95d5f240abdfc55ac2fd4fb9adc34ddbe6cbb38a9f193bc8f28c12eb7ab89eb7a03ed785a7c35f98f0973d3b14db74d27f25ce1bc138d4ed732aac2065ea32b3925c947b6f9f1b5a44fdb458c37418dba67154f1a26d151137e3cea522b5d328514e46ba2a079412155415ae07bece54ec56f47ceb6584c88a96a97c52a53a0c554673cb6464902027844f7520dee6abb6eeb1231f794e421c7106a0c67d29dc395fb0e662ca07147dd860e5fc5e72421e05c5a94c20d04d5a8dab56538da26329260a2ad987d877566557f4c4c1086f0dca21d4d91bac5a42a7cd9a85fdfb6fd55b58c4ded2e9346d80982284d8836c824a8e8679e3fc82be0e778dff44ad8e0f47dd240c9d2aa697e05bbc44ca94c1fd88913d91ffd3015840b5bb096ce5c560adb2d10894c8b90d031df17a758d308a45b48b14a81ba8bed9baf29d54082b60513db7e07659242963694e5b017d0b4844a1192c38282eeb35341a9db20903043ee231c4992ad8abcb788a058ccd83575f980f53621b6b5ee6007e400baabb0baf88773b2ac1c344cb09335a5a9d4fb34f218c3925c93c476cc4bc514c8c6810abfe371f222b442b647ad287573b3c4a6ecaf7f0110fbb8dec267c7351bdb5251a45048246c6e90db35cc3b86a6435d4360c88174226e3d60c5ec8729636b24e01c6b003725eb4bbab28e138b620d88e409fb330d22ba7d6c4eb9b6ec6a1f9f31a4999bcc8ee71d25cd6efc1c39f5298835e9e7755abc936576df3504d676e51670149a2db5f1f6d0aa391dbb23368f60ac7d574f7f960d25650dab8e6969dddb8b97dadd423497840ec7b8efa3f6ef0060a4559d9a538ceca30492a7dfe194e689716ed314df2a3a53b1273fd0b6488b03287b2c00a38b24c46676974254dfe59d41efe70b7a26a92aa4abe1dcebc093148879473d41c3d25b4d3da95b8b12cc9ccfe21abab96baaa7b695833575b799d3204011e7bb0217334a271d8b28a467b8f8117aae61b3b7cc17e5250384aed6d87fbecd63aba8e4761ba5ba65ff87c7151ab4a8a0204a944852f11093eac5a9a2878dbc1c0498f038ac4e084241a21a8a24a6eb8d627e3fbf1c3892d3eef49a562e83e32faba7c9b0d3d6608726a8ab013ba931ec3f644a766e2f53fd31cc475f58cc6a46e250ee666a144772e276c7c3551af3a0724cbf8f8ace042a47920693969cef20d1565bd08c06a35396ef230c53c2686af7246be4c0bc187a476a4f546c1a10cea4ad60c022244c6d7facacd96aa522c585bc9bf659c2acc66f63bd1a537d4624b54bfc2e0a9fc92b2fbb95323506b1cff0acfa4eff14f55335582f560051f235ab7b3e42534043a998bae634b273f7ce403adc13614e1e1a62286de635df09115704216f4da630cbcbd7ca0da2598e7b80f5701a140dd9488e994f190ce9033370ad1a32487c9865c21c2fd8f5bade0960789c26c3d484878e501fee3fec50e1752176694edd531c0fe23f43ce2edcc290f3addc15d9177ddfe18916ebaddf8d307d79537ca1e00d7880a47ac311c95c17cdc2930c046fac96c6875173fa036d58faa15500d25ec63e9f29eb9a1f37ef166f962582ed5161fa291d35242626f153ddbb3d4307c3d3230d27dc6e57e2f475f2cd93b32ec7d69a6cbae8c39358fcf8a3c17c7305787cec02c709d67ae5a090dc5eb7af8814199bf5d9d5b0ec9af12a78ddf0b093d0f46e4ae8707a5bc65d6c3ed918d43bc5812d3cf8900c0b09a6d2330f9a063e3fdc21bc1ca9baffee6abf34c290d11638defb2da31b09b3a6a7c03c5aa422f64a4f241befffa67b8c3bd18416ea0f07fa5206681f79d15444e092729436383e1a2ee8ae4635973ad6d22c2fc076b10a097797de3fb794a54bc310a9e1012b350fb9aaa5b431e28743e5e8a766e9207d12651a7d9cf5baad9ca9cb1c5f55d63c2ca378acff91b7625cb1943c45a8917242394f9423ad188696e18b1413f7059ab9a5e354a56cfbbc084dc7d5beab127434452bb29f91b50639ece699a000621a186932f7caab1972a2fb6176a79b09bd75bb0fd4deb2fe8f6f1d543eb3e714259475a31aa92b12dcd2cb7a8ba639be4742fe0d199322e0f5be7eb8f1c5f569a592657a3423b4e5512b4a55974e9b86bfcbdbfea507a4499c6308772ecf3d8830d4b9cbab59bedf81f6fb334f6bdc526afbd08aef8e8a061fb2e72422196985c7ff2df9aa689b2715c37b11a9e1a1d4a231298ba3fd0c41d7f319f50c95a12f8eea872f9787345714eb56a359cd3e5b6afa73512b32d330068ea775a75dca0b59eb48cfee739a4215cc3973182519aa19e8d180e6bda445c6a76fc6104179af319c073f6ae7729ad1434942b99e2e5b71810cc996d17c3151debb2eb9d83b3c5be7bd6fdb1f1d38b46545a964f9eff060408998b14eb2239ca170cb2e47de95803b9c7c4b85b0c5bf4d92aec9a56d4def3f82ec64bb291e9d550d3e6ab516466cfa169d9d684b7a51d59134d58b93ce0816292b65dca1f9edd56fac57b511ece995d872c9a1e5c9d144aa95d9d227d3276655728c0ffda986d4200e66581824614bac014eeb8c65e56c2d058e205bfdfdc5d16d87ef32c63467bb4b9ef000f0edbb2ce04bb9cf05518e40e3fe9d823f92c6d1e689776e5f4b223675a360da5dbe78109fa503b88dfefed1c96986a8ae36dbf9fe77199abf0d7b06195a5d2b0c8dafed43a5463dd49ad9d743374bd24d82e4ce4bc7ae64bb8fc080ba75d6455bb5ac8acf8cc8ea9626a7bf54a96fdd8aff6e98e4b1d0a35645e9a78895ee51acb0c0d6dd6f4db1a81be0cf7cc5ab0d4d45349e98bec4b93adf7c9013a7f2ce8b8cbdae5bd0cb4e291e250cc8b764c88f17b2a1a99e86367ff9dfff0197c9d0d005240000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/stress/64kb-08 b/cmd/precise-code-intel-api-server/testdata/filters/stress/64kb-08 new file mode 100644 index 00000000000..e23e04d531e --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/stress/64kb-08 @@ -0,0 +1 @@ +1f8b0800000000000013755949ae24c70dbd4baf5340cc830e20f80e8617b660c082e0f642ea95e1bb9bc19991f5f181eecaac080687f74806ebbfdfbefff8f75ffefec7bf7ef9f1fdd73f7ffbcff73fbefdbc9e6ffff8f1ebeffffc133eff353de9e975ac99766bcf792a63b5da5b1fe733fc3b3a7cffe4810f09ff6aedbdb55ae063aeade439cb7af2d3f26e35b567cc9cd61a0d36d5d59e95caca672b3c6edc03fff22967514eb3ec21d27f2ab9cdb6ea688b4f6b698f67d1571924ec82d24a1aa9f5bc8ed6bdb4b2408554ce939e0f9a963996376b89546f269998dc5f19a046733625279796b058704645cff1e1b7b473ce5805becbf558fa80bc495af30e3eebc8228781ec8c8e2a69cfdc8bfcbf9e4222d35e790e12de5349d98ecba9adce3e49de336d8f6412757959020058f2d69e8e8350e43c37854483cfb0c9c54cf74e05b1f91c641eb44fc5425d4aeeecdf4418017565255a334d1db6c6e9563b0042161c3461d0c98183c4c62092c8f52c3867249225df776f8b9e99c55d0844f1d122471cd6842d228b432820d86db554e54d4ea317888f28418016cc8110da9553afade99e5967cb8b308331b173fb4cadb8c500d53c93b2f74daa4337055efc23ced45a5622c58c446ae4f104e3d9e2a6873b0885885906b170cf05728ada0ca7a293d9d7aa6276d02d21c9d4e2beb27464d1d8e6425612356f3e779d178310b4ea1e0bc162008fdb2f5a121066ba1351ddb5e4b7c118e03b201a4f9f675e91491f94ba5c0c3b4b06ff30d4f25ca54f452283534c412737a06b032b14dd08b4be0a93231ee860ed430e1c1332c540978471192bf7d95a08021c4de9670c9538211cc745e3a000cf5a4101632d7aec938308048589f295d32c0bbb7dac1da9e38adc15129f4e92af5f186d5e4a42d88578707945fd4e6ff25cc199358199ecedc390e49787e492422ec3f41701b6464fb3df6f492d5039181a70a2cfe14b459c2b006bcd5631499c906a6c2ef8bb14c64b5cabc0a16718e23355eb5cab2f596c7bd09a5237083b18b3f38ae40f38b6048da83e5850b30fd7e92ca46928790a2b7a1a87d5d08494d17cf603a6f8e07850f9cf4044cb672da42acab0c77531946396bab726534a939a332d4ac4a93ca0aee432abf149d79cfffb107ea0eaa680956db34216b5322ac69823c699ca02a97b25f7d1464fb963b59c9d76ea799f1c144d856df9547c6e1dfac168e6a08526317fa866f6e75bd3c02e864d7739a0725f0a8a1bd845abd8cadc5dd1913d1ad5afde28218d323a53569b00e9ad28862d2a68ba7409e1c54514c67ebda3eda8a360038db9edb1e47cc2dc4ffbf7bc12993012007c353e642fb95198a99bb4f1a1344fe0bd8382eabab601798de0f1c8888986644cf4ba341de0dd31eb135b5775533cd515205e4cf2c7eb7df0b3c441c9c9571e871f2c29c87393d48ed12957e0b56517f6153ec04b85163bba220e80377c74e5709d73b2762dbe8b5091474b2df53e7970e0c861a1fac0aa13dc5713821136ea4681f814b0ae5fdd65140fdb4a52c46b65459a3261594a2eb169649c8cdafd9b022d5ba6d0429b3dda3665c8df037a7e344079f2bad6205a0137a0209093ebaf5b446f2cc2f29ddc201ddd8f91a00fed0188685f74ea1edb5eb1909aa3d005aedc64da71a05c1cbfe498c323b5126409f651acb4441620c95027e7e68ad2468ac8915d578b2f078aded20505dc0a8fe49cc83196389a1a5ed62b0284f6be5dce1cfbd0c735b5e13e23610b6a98ed4884b3fe087585dbc9e0c8b9c656a2aba4b183ae82b7843d64f23e61f3799b6190430799ec0b52c6321e94cc7cb8d8e26d90f0589abbf661d96623c2c5966f24eecacc95c845d4dc70934ac955cac4628c2e70d9bbe91d39143623387950f020ed261c7ec81c3181856f3c2e6b804a7e410dc5854e8c788989059e76aa4393edab6dae9004f4a358ae33832b5185e148413d6181bee32e34368eaf39c3156ac551f29c782d72f03c12adb1758deeab9917ee94a44d5b96d73d5132477792236d54a2677d511d1d7a08ed160358dc2b2542a7c9550f8d342f3fa02d9cf78902a4c329327259b66efca482615589d362eda3e7ce4d8b3a47ef1ecebe23955c704e04443a4dd476df2e6956598260adf1507a80966569c334de93ac90a9b8a2878ea183f7ac3acb4cea0522759ba419b847c4d8a3f6e378505aabf790c634b3d0b88034eab4afbab13e4e57dfd7622e6bc62ad72869b5a5b14120c117099daa194e923446d2115052a7938a86e3ee0ee415388de701e03b811e3347d2a952c10d26be202eb90896398455e099b48221765c1b485233378133eb4ebb1d28db65c69c2a4d86baa565e934d93836c112277a41cb4359ba5ae6ba3f85ab97c2e755ebb013f3ee66376440a6b7ca5d3c665ad9aae6e7e2a283e9265b8798e9d2492c89341873a2f90aa9374dab0da0c59a67d4e147edf730e2347e70cf5dcdcd78dd66bdda94e51b052af36f68f842542c17b32317fd56a1147479e9137dc2504a0fc7fde3f1b65077d10afec4e07d4b073ee9fe59441583b04d9a2611c0dca84d2650901c4adf34ffe7bb229098c601740be394dc292786bc124882f3681d38393fb0a18b5b84ec5dc3d3aaa31c6e935b165ee9b169753f1cf899b6fe0e92ce08230e8b19a529efad4305ca83f315ca655b6580261083b076fd9dcb2556b987092ae152726a12367d5d3623bb3b8ed59d624252c5d102fd96f8026cd9108baef39350ed0fc035c3ba01779c6d5275f537d6389c009b2686fe467790f3e1779bf412b63cf8d3d5473569c55de3f0228249d39c0105889a8b7cbce52f5b7156edeeb4e7973eea3964fe7f0df6cdf9922d956ed13e353b60ed7e76f9de3bd152cfa961ecae2bdce7335f4aa5ea4e9b85b96bbae4518c8a0e28c299944a6b8979a65cd6e3ecb0cdbd50dc0417e275036efaa5dd487165daf9cd264f72f2a7999a63882b0261ca786571fbc56a5d979c00913e8491fc7a7a46c99f70575a7da1e197b71dcbf8cbf5acd033ef131a1a3c9ec6ecd3e8fcd5bc98c25a28afb0bf41298376fc71cdb8173a009a4705ce919db17b71009060b93e367b07a5bffdefff44a5c57fe71f0000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/stress/64kb-16 b/cmd/precise-code-intel-api-server/testdata/filters/stress/64kb-16 new file mode 100644 index 00000000000..5dc0010c1b5 --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/stress/64kb-16 @@ -0,0 +1 @@ +1f8b08000000000000136d5a5bae643b0d9dcbfdae2be5e9240c003107c407202410e2f201f70b3177969f718a56ab4ff7a9ca4e1c3f9697edfd9f9f7ef9f51fbffbe3bffefadb5f7ff9f3bffff6cf5ffef5d36f2a7d7efad3af7ffefb5ffe8d5f7e5f3e3467a70ffeeed5ce699f56ce6aa5b7cfaefc1bedd1e798f4299f869fbabaad26bf35f97c94439fdee71c83863c5f67fbd43e1b516ff8be968a1f67f02fb46ad91beb2af53d3ebbb43df67d883a0ec5236d6f3f9bd7d602e1488f2b9f9f5b1d6bec4e78b2f6d1ea5a6d9b8022cc5d60cb2bb63dadca2d0a95b58e48e88fce367ac1317c371cc7329ebd79cbde4b1b72a84923e2f19f5d662fd4e97c5c87fce9a27daf88c7598310067bab068a6e8625151f97fd6125f837226d6fd803c7e1e83e787565096a197b2ed1769b87558625aded86ef666d261fc9ef7bd6c35b60d355b17d9f34ebdcbcc9ea6b88c277c8d5ca3a24aa6c6693a2de70aa08aba62137112f2bfaf186f2e4e03367996a37f98e85950da9b1a7cc5679cf2646c577876a6cc7abe93162959f2201d69647bb6a623163edbdb1f92ba41f6a297640285c1e2d074a51cdd1c2ce755d132ebd81aaadb23374e253d90c934a98a3550e083685c9ceae54768175e718265011a5e1e1de668781dc508d6ddc26cb88ff0c2c628783b6cbddadc4c58f5eaecfd39b7e13d761f72f6db2143874730cb15e8b6d90dcca2d2a12c0c4108b6c992f9aa195ce21f54412db74eca41ac46d082b61e5124308b2883f7c205f62afd942257e9c40886e560c4f56a7b53bec29bfaab7d05c6cb701c080a76df108e2eb105b1b0b0e626d0e883d92dfb48a4f713cb9d3b173d7dd86dfa46ae8f2f9837d79ae82e0e147e2361c878b8f541fcbead0f8152b1c453a13882d3ea099f37d288b27d18bc7da2eeaa7fa8189827bd773e4770fe72a40090fb94671ede1d729e1a862d16ae45e0771111ad7c27c46b8554d21d02e728ff056411528a30f126b3df7362fc20d4447906800a4d5baf61d1fe17608ace43803aa26848f94503bf53ab6a8448211569db3eec3d18190aa0d41c076118d11909aeda3be9af4eba243a3409c7e46c20dc54228a1afce52ecb813ab906dd05b23d58462cb305c8f40abc4379613a9b48b78f12f56926925c00c9b74c42c04ff51b899892a6598a914f6e95fba4fd8a30e0cb517cb0029abf89fe45bc95b1f08d4850b81ba18f7c4cd1537da2a1c86d8b4559ce8eeb1769b4b22533e015ed6798aa76b099c019444ac264c609dcded98944f27030183969bfd37cb19cedc97999aeec7160d8a2ea506fc74f6240e717149da754a36df0399e5dc1c860786e612f2e411de078b9e97e040a41434eae66ed1a6becdd1a71a77fddbba94ca34c196ad69ec52a1010fdf4f1ad7157c26f32e8874866acc8ff0eceda21bdc57419ff6b9aca18fb2b087a65d4ec3ec128528239dac65e2a666b871e3cc8aec0833105d4e827f59728b16e31a5f9caac4c50cd5c5e31b5d7762a8e905caf40500bd43491f9a2a1cc2f818dac9241e47a678d6b06563287c3191a45914a422f09b87e266711895f11f3ded9aac248a7bc3167054ea2c1257ee06fde637c64c9335b18d7d901664951a5f3d9e9852c8796256ca4ef0c55602ebe4d99db9f286c7ee3067a5030ea281dc7bf63d793c7972ade2e7c447053cb893291fc0296b7042335e2bd0e7be8d3d9b93ecad5904cab44f259c9ad92ee193fb847e1f30c8a154f827d42dfc8271649b7f175a45940c8925650ccb343766b1146ed4e7521eccd73ca533d355af0cefd990b6ef14a13f839e00c4ccf702d7e7ba198dd93fbca308f83ab23663519c947d7bbf0a3eece7389191bc74e3672b69691da9ef627a389a625425dcbab665412e80e68ef2035afa6022c1ecac27dd134cd3c4cbe8eb8b47a3aede50a260da9a64e6eb761b54bdf16d27b812cbd9ab10a740298b2ea0d97006cbf7ac870f72cd287733f3e90ec212ba113ece41b005486fb78c64e1dd98ce4341b02bf3bea7ccf3326c9892ad3e134eb5e72ca9f03457baea4e2a018e69e8651210aecbae1f51020624a5c9461ae1b0b622f13ec054201c1bfa022b2eb920b5f207379c193ab43a12cf461dc13eef270ac1848771cc04857651d9d584ca7e132c25246cdeeb20b324a3dd1bd97fca53d63bf23ada1b028a8b5ecdacf6b9ec84580d12c574d75e1514d1da18bb94acdd2fb9770f174d99336a1228c3081a29aa28e8dc3ec393a4c3ef17bd58882f509b6afccd4bc81fdf8a0c9972bb202d02e4a533979eddfcf173055d6c60499d2279c3aeb4fa2797c9899efd8cca052e3e4c571726ad408ce8f163f458cf7e0ab787b1b426eb2600a6514d14ab5b743b78f47a8a0f65024da0552efcc3bb92e01ef374d4b8eed97a7bd33e0716ef55dc8fc2a05d2a7718a25b32ba9e276e2ee24abd5c176999563e2fbf66fd6003f5f15be4e496012f93d8b5ea4bddeb16827dac59949e3e0dad8b1046951f1d46bf605cdc6530986304e57d9a177af0d016c95769989a4da663f95c49318a963afbc73b283070bf5d03bef2f1b0584a54e02f64f8a7e99a7196d93c80c52963046b3b7dc6a729fd29e3e47d676705df0aab2b8f6283d3e416085ba85b05e471f97228c77ba508a5305da6e84d05346b442a490a37c4f147f0c22c697d97894f5b54bc8cf9b519d27903445c42529d3af3e4dcc9b86254185a1feb6c4e4e48abe63966981105d465c3a236269e1cbfe61292a010ae9941b1d2adf8713507a2d40b03bda58a374e71661fd906f91dec035f29d51b92787218f81e5c6a8e8b517c935dab3ab3d63a568cfa11f1e457870405d781dc76054f627c05146053324834e0d8b62bfa077c25d154367f647e3941903030b40854ed42daa2dab348f1e54c364749bf1cc235a1943ea0e856e5d117c5f36b733048ec4a0578f734874bc5ab7b5d00c90fba47a8af88ce74a8dcee282adcb9a676fe5e15fb356eb8a7a4358b079c0607432377c3410ab4cb53524ac40da7f2239035f6401a6f178d41426e0321240e189ca678b1cb1e8c2c5d85830b6ca89ebda308bca14d5eded4d4ddf14be88ea2ba5c81861b472b426eb47730d027d74985e81ddce8f9dd3ca3d9bd9a9b48469355dbe15a229d41a7f8aea37c37ac28c3f9ba59fe1e436fa3a51b16cdb615f12cca75ba01f8f24e5ae615d619b79aa37876f17dd57cb79d341674f8e41bcf22ea94ceeb6b7b0add2a3d8ccb8c06bcab7ae96ede3622a96b3360a6cd79aa308b6607c92e886100bc25b8b7db24a9451158f0c01bbdb792face8aeed143c4642ad081b3876e67a9bc2264d0f1d30c95105007952c3b773b8e620c1087ca1b9f562fa1c08732bd452abae3cc2a9516aab11c3ddece6d0375e45994671f97873dca4855aa078230289e87d5b737eccd7ecdbdc1c9ee12bae1148d52c8eb5323ca74ed2b5e7d9e9668ea3a6ddfa06257c63328573befd8bc58e724b5ba14b0972519da8dd5a53916a320b52229ada22fc7e8fd1b489c1d9bf3b26c78f416fbdae5807cdc884afdff552c07ada1ee64813c3e0a3e32245cdd5a0ca8f9a546b354017f1ca5bf33c82493d62da328f673413c83b719e08adb4b563b9c944a782bb6c4276bdcd0af311068524d3ad63358f334ede1e9b7281193904f08cae74464e6e654264bcf8512f4dc180303b9ed93e190bbf3f0136a9b6bbe40fab426b5e05e72d3c9bdc0a7e9276debdc0df2a74e229c5f91cff8a36d4bdcab4dbd8ca7982b84cf3e724e729ae5d38d3dbca96d9f791bc097a87b5a7b403480e4c87df9e4a63091ba00739d31125db22ce31c480fb44cf6d55418e2a14969d5e6bd97765a97c7f2208bb9cbd6865a0c6a449f3c77a94a3db7e550d2e6dc66e1b51d6ed71c6df21cf4b37d84de8ab48a94c469c43409ff7eca1945e70bca7fbffb8e31c74441528ab4bd0decf527f7b334ab3829d69b91341903f2d8256548aca374078fad68132d221483ed0bb3be2815082ecae1a740739bbf9d67ce12161e70ef212c33dae06a2d3829a845bdb4eda2a6ba4a8c2da3b76793ccc31d3f326fbc4fe561ce57d9cc9ec1532f9dba4f1dda0cee1b2aa2519f2d86aba909e53b2a4d1b09067debdc877e6b4c8f52e5ae5c421682cfaab5ae2b1bf86fc603831c277b635803d71bcbfb9671e5b2889ecb30f50ded3ff9c437858e546f5343aadc298f273dee6e709c2c6d576e36db9d3cd5b0c265c6768b4ca2f90d071e406d4b3fc8df20018b7263ae7eb2779982756823575b3c365e3d312b299c7decbada856cbd39ffbb9b9ce8af92dc2e49d59b0158658a991c553b610a44246ae33e4d6a230bb5fd142776e9bd9577a0eb747958d6ac8d756e255b2acc6d7230a5d1a0768c52504b5cb3adbc4de0a49113cb2df8a815d6cfba3d9dfd46ad3772a7bde5c18a94e9a896be94a9ebd3db97b8444571aa4ae2cbd6d5803504fd3eb5489f330dbdc35ccd1f4a6d57beeb1cb789245944860551fb76ef3c021c64707c4884e6d26bca7679b22254573bdaa90ddb6ea760e78e1ec3accdbe9576f21b32700abe89f2de54c8b4181b69652ab3aee8127c0d063b37223436ead3af636ce7cc9bdea4ca9480c6dbb7ba258976b35bb1f7a9de065eea5eac69fd868ccad23b9f1241df8f3dfd61eebc769b7acbe4f5078df5f49282d7567afb9e96b798d4a4e7d254c4aa8f18e1acb7755f19ca1926487ba860353c44cc4d98e76db0cab4e19945dc2fc3806f0d20ad0d9b88dfdc40e9852883c35be63d0d8c78e3e169405b44f96619a04bd43ea8f3243b73c2d26f6ea35022b492f4fcee2831fa73824984dafea204542485d26d3f71af6899636b57746f76c9612fd2c46b479a70a1536d4f6b9b56745e4274116d9608eaaff7f0bc6d9dfa6fe5b3a0d42e5dde06f77047f7c9d6f42b9fb274c0971b3f831f2ac67468fb7b0736461344faffb6feffbf3b92272d75788a94c9fe7d7dc3c7725e73c768db9b5c421f50481d95b32f6882e3fecebfc6d8af8fcffb36127f2c24b34e26854e35e5a8783950e33e86e9d04877718bbdf1e7970741e92d8c730765e50598783187e99094a23ced5bd266b1199e144696e6d3cb0b25b976ead07d95ad5a8dc59de5fd00d86944836416790128b987a5b63b2fb3e2ece6079be9fb90d306e39ebbbfebd3426f779fbfb704b336336341c9594794d5773017ef5aa589b33ba5534bdffb0ffffd1fd047493f582b0000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/stress/64kb-24 b/cmd/precise-code-intel-api-server/testdata/filters/stress/64kb-24 new file mode 100644 index 00000000000..4301bd68aaf --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/stress/64kb-24 @@ -0,0 +1 @@ +1f8b0800000000000013755b49ce744952bc4badf3973ce6080e80b80362012d2410a25874d7aac5dd3133f718f22ba15257e597f95e0c3e989b0ffdf7df7effe3bfffe95ffffa1ffff8c7ef7ff9db7ffecfef7ffded1f72fdfcf66f7ffce5bffefd6ff8e39fedd35b2bfd83ffcd91d7ca9fd6c6ac79d5fa297dcc6cf393fbac7d66bc689fdc7abc9147fe94d21a7e9afada3ed556f7ef6aaf9f6c6ba4963fa98cd24bc5e33559c2bf562d19fb8e5e8a7eef05db4ecbb3ce78a97c521d58f8f32b5b2ab9b785176ae7963c4c695c3f25c389bb6f8dcf65d43471c85f992fcfd2b15c2a35a731f2c423dc5427bc0fe0147a3e95d92100e305addb184be7deefb65c8b61c3b1b03cced047b23571ed24c12dabb57207dba7c37df817decb786a5a2b86f5179f77e1e9d964b85dd76a73f6aa2342acb361cb59f0952d97965d619eb3f351ca664dca7fb6d1fd59080dd7ba672f79f06210f2a46e4ae53ed8324de3d756f5aa9faae6b6fc203967293cf5b16a4ad84b873886305b5a5c368f01b3a1204beb2db559a9896a56654a342aa3eefccb82773ea9e19065354ad872d7c9b8a51e5e38506c3f8e35e0162e4fac821dcc60455465c1cda8d42f859bc5a375f2efdc33ada6e5247dc0e4f84c5d1d82f7d57182424bfa5c732934ca4f92d534186d6f14db357d2c9fa9d8a39c46e1271e329592b9106c85db8705b84fc0f43a6430d6185a9da75c06495a4dd77668e338589635362c5aaa51c8bafe58a5f35cdcb975fb8c54ac2448b59505b94c5a85e4d157c3a35c022e340d16d6a4f9e4b647a16395925b19e358812c3b375e006a36ba1d8593ed98b2de2db5d489358f51e2ecd8abe8935fb5e4fb81ae6a73497638288e21ad5133162b1e49eaeb546b1c69fb813fb61fa250b0f54ce3e8eecb04e059e3a8cf9fd5316148bc35ae52210641011f821556691ec7ea815f843f19c31ccd6d4fceb9b16b265a77f6eff547a6bcba5eb306688b8b4186383e2e0dd383a9093168791d98864f6e00503a4e00331af85c60d50e0e32bad4ebf503d725704e2f5fc4db8229d8ccafe3c29ac9af3385f0c3e0df32e4de7395402959a8bc5929dbb67fa58e53a70ccca63375784c77d8e74acd140f6cdf809654c33cd6f8c661ac8f7f843f7897f6dcf15b1c0f51c6da392cf6488be050526d8ed6e10d0dd609c31aa94a495276cf0b8f49f7049c304d37814e34924925de6cb4859b5e23e25968dfe666170045279332e5e2551a6a1799122457aa9ce98d2e75632beec6b8075f49907a4a5d4e36803ff84ed6715d4567aa8eac8c32b6e1df410218ca7b75c861121f66a1c4f1a1b534171df3d7c2a146e39b29e40779e4147ef1c8ff895fd52017de6f00170015fbc785fb39d42b4a4d84a97eaf48e166616c0e139071407a2902ea757260d00a9becc647f785f77ff164979c20c491a6a085872fab645c0494636c87ba6020c5098af10fd0434a395a2b9fef607fdfe4ca381f18c3ea3a1cc214bf39a1d6c5446f0a5be16dc6b010e831b573bf6b29c72af01f40237e8342d7206e034ce1e74dc281c17604fd32e8d645ce3433d0baca3cddd7124ed5c60a2311eacb7460f8a92ddea333b40aa9ea9a8ca1fe873bc720b6f955dadc58fa1c7438f43a1c659384dca533753579af07b0fd542364d3fdab60570514a907229a006cc230d7ca4f3c20776af9e86064f82d632f4e60c2f4a0368e08525cceb4f350a2bbc38eb830ca27525183789a5bac23afc304ef9d237a6c8777d52f42c2c62160a208cff63a3b163a7b33a2fdc6203ffbb113dafcfe8982c87232086c1169df85f824f5dbaba2cfaa62406150d9630364042fd86cc989d136ac1d1413bc02b24b02d20df1970c5439d174950ad8651b0e87478c1e3d16633831f8a5869b407741899f0c38511620e66ca83892c9713605a34068d06e894e9f1721282cc55c6ed0a7313444ac7426ac7442a17b5eeb27b61606163d6a027c8189b392e7c04848806587909f30d4e66bf88cb66db91beef0eceef1eb98bf1d75dff70eeee58d420ca0e9cf56534f787e387feb0f70a5510c6135d0950912840b0492216e416ec57b6009113dfe3b179f38464db30a2f86be7183be98acb8e7d623ae40c1d2dfa56e54c83c43ca0f1422842d050222bb3c0eaf50aa78af42f8ed1af65de67139125f08b91f7b22e185eaf1bbb30c5bb2b0f0e0e69b8f5a83aa43154e2f24e4b9afebda90e986094c8fce9b84e12c399061ec40fbe452fe11373af02ceea5539cd82273e4bf2bd96bec5ca14b178518dca069165e73c7c6427ee8bf067fa7f34f451cc0b22b2132c340f6352e3a85a6712553ee860f65ee98b06f0fe689b775a97bd208a920457ba9a3061c1bf920842ba7d49a23c82c6d05b47e82a1f56b68fb11787cb5744155264d391f88d42d735104d032293f46cfd7a85e678d8e608c0491b3eafd3fe52d71fc8b1785c5000af886363fe77bc7fd30422b02d281e732c7ced6a7e7ca02614340519a991176b0f6c88775e26df38559f4e88e0c502b92b6ee4efd8b7113291c3d4af20ffbc121479f0feff1a55411283bed6fa423d0c43e3a6e0ae5b6d024a5451248fbe08a14d3178f61bd049e92462083dd82c3fc821b5cd193f3e39f6eacf7911702080f309cea20a15fc4aa431717db5a7fb2b82c0c14d749dd36f23e0eb6fa35502630999f1ecc86ceb8bf0bc0812bf4a8633e9ec68cdd2ec89f502790278bd5661b6437e4a755fa5758ba37396977e4819f6342cd5f9eca91ff94b2a657c804833a4f18db313170ded9c9215559349b79752fe291bbc6207c09a9789053b4bf12734259959af4c360ecfb320dbbaee306c2b2d42f4939210c12aba71c840bf6f9c592f078b1a750e704f56c190fc24c7e64144f889d0b38000b97b1c825369ef811a0abf00e0fa608c8cb765e8a34e3b32303bdf50ddefb89f9a70c22121003f3626de350296537c5f91788857bcdd1e97664973133dd14892bd21ae61f3bb6077febef11efb18e1a3ccc30f28acbee6d4e2186da4b741bd5f2f217c13377a8a1cf3b5a7b74cb8a1f4ee05e425296adc6f8726a4dddb35d045c2840faa203ab4a31eb42046acae92b0c8c4251b5e3614c612c5ea0a5ef41b15ed9e835f517d7bdfee7954da58249354673808c9c1246f39d625188045132a0d25a2408a708bb7dde6106b0acf8ee629c5d5ac00559c54d8bf0dda3ec7c8e75177b502e39f0c6b58310ed7a9a48ba21c4916e0bc85aad276d4aef921e2e77a4dee5a1b07f2f27bd8fef92653f0637fd18100a9c751b0d626c276fe34522d5a978f11e57d5931ca517ab3c1e73a3aeace2a9dbe8fa371b03e898d59d3cb6fe1544607b9d01df581e28a4a29eb48bae3deced14e9796fe22f1741aa9d49cf3c4774bc3167ae5191f70a43b75d05e8821c7bb220bb001511461ae74751e5ae30587b173f6ea9be1994978580fe6eb2c070f3e416b8a3623b1900b35a28346d3c12f22791fb8d0d0a9c29ef426a4d27ff6cce3094114139c376010cd94790963659549d27d5828caaf71b1075ba9743dd8caced6ad007ac7f2d314215a9559bdde517f726df0698440c1bd0174b6dee0da9f4480fb6bb1f95a60b78c139c0d34db2bb0609a8c8e329d781a7369c083f39d1af8ae657ce41058fa2588c894ec6ce5110122cea047877d8e18f78965184896c490f00bcdefec68eaa368b79227dad73730715ade1afb653b22456bd548a0d52563cb78e6adaf02ff702da6b30e9d801d26ea593803dbdda03b78290990539dafe488fb8c95e720bcd6bc08778a854ae585177f5980b4ca322e5f36b7d57e22cd717c2e6261baa87ec504088ceaffcea93716b9d5d7ea8d0b2a940e3a973ca270623eb87cadf2e91ba4fcc253e914a2aead0530400f346626682c52bec99ed3027ee3d5897b35cef0ed06ce1705ee6546ed52f2b8a442c4abd0c1074401e234b92fb4273beb5a7af6e9e1dc8669a9487079d5f60d8c843e6aee82657b1b0c5419f802a9a8cc0d352f97861e3d9e4091ec5b38dc8434cfb9812f0c16ddccf18f7cefb2a71c07be58451abf8aa3b30e11b6aee3850c221f05771a65ba33f053a904209e09643584061e54358ab7df1b8a8713c85bfaab703c72e45f9ae86968051753db8347967608f3a31483f2d40ecb32b9c4ccb6177d3ef122d518b7aea5eddf39c108b5ab523bde1d8de80eb48ee0ecba28fcad1aa4ca51ea6a2cc8015c5de6f7db082d833caa9e21144bf9e50c2dc9990dd2285248825240d4d19f5e3320a02401284b427dafdec195e946224ee8a465ed9e3d19eb21a157f9a8027bcdb3584a4a8d495f60be80a22c78ad80239b8bcef51bf31d24dcfd629f9383003d897dbdd6e7dd0b0b1c2ea4f676ee72335faa4454dcd48b8d387b0b8e015c3197904d068fa808821385672fe20886cc63f24fa3685fe1fc99d1c302ab0910d4482f3a345e78d474f97e4c426c6a2e23849af09deecbaf74ea3983e5a34d4e9585da9cccf6e98777704942bda3887792d6fac3a655146615839a931ae1411d96761c000869f68bdf35375d959fe61d57237bced069adcc64fe3d2c9e75b3c4d3c0d30b34bc4b7eb00e2616005c0c0e841ed3a1f222f89fd83b00a725e7bf21d257732b6faa1e789c540ea256ad545658214c1c94328636517f578eb97bd7cd7f93cedadb2551823b9f99ba1ec3c47096423b1b6aff6f3367fec816f46b4a023a44615bd5a907760ff29b7d00700c7a05f7cdb0b3853000eca36d783eadeda3e395f17d5751b7668d7dbca80654cf37451bd58157cb7d7759b563a42eb0f282588c6dceb1d42773e489d7802e556228f3d346846388bc65982d17ebe52f1208d3795df35ef60305e581afdd096af7ab888f1d3a5aace263cd70dcb3d64663da9866df85a39687296853db927826d8579af5351fe5383c94dbbc654c94ea87eb87a5c30462c18132cec7d8380a6403c43dad599acdd7e76b8590a62a4c2c524e056d6b815876693c6e316bb3c85f9ec31a36e5ea2be8d175018e8b55a64c1a7de3a6be403f573b03505612a769bd02a321e1a80a4887535faed34a6ac943d329356cfd840b4253f857d671533e1a1f26f1db266d583e07f35185a642348fea8662f44c92665d443d1a6cf675844147cb45337a80482cdbf483cb05fe257671e49e9ec0e19cc63548448914e4726f209e673d2a0a04b3ef18188d2db3cfc56134039b4e0dd29bc35ab175837c9f614ff7ce3e9cf69ae45be32b3edfc0a8bb42fbb7f0d637a23c19b93723d86578fc4617d9c68cbd160b2dd558cc92f4847a52af392d5ed8bb89ebdb1d7f2d574bd53299c956b73a63be0b05f56312ad79b043f3fd25e39337066b1e0e1d34ecfacab0321cfdb53304f05580ca087e169f0aa345649f508228883da6e5e6db05253cfc57c1145893c61aeb06e3cabce20fa742758deda283c843d0eb87839b3403e2ac4e9b088909a352340c7bc113dd3d9ea89e63bff2c5195f58a6f7d885520974894d95237cf1fde4458261800a25e274943ccc77150a07e35ef910adc71a4d1765341a5e3d06bb4064e1154316dba87287d8b8c353f95f3f40c8c5d8200a3aab7431db49fc6541f781f0d2f8df2b44cf1c639258f256ab0abbc392890cff760a5da71272f085558cd1c41c9dd147c7ae563a7156a67c0e96d7b38907a47103a482f450e7ae1dd1137ddf103c96e35ef20f7a967245d8cb363408afa457d285b37291ffdd8c9c2ed33ba8a84c13862404eb8f2c6645c532c28ed544d536aeca848f4250c8bbe37e03446818f4b5dbe40c4ce3442f3aeb2ed924ce3233e65e4dcbcbf89bc376025e8e913b36c7bce98253a034c7d6e7945d13f66d772e9c3c720c3709e10e8b926577443867fe21e452dacf2942cca9d5148b759c1c0935b3e1d750aacfb98ec4c0ad6ab771f6485e3e43d53a3d462478729e80bb7f02cecce00622517b2fbfc7cd9300780924a3b3bb63cad3820d114a3c890c8face26146f5bbf33974ec83422b0bdf7a92edededf2966783338cf37353b156a3ddf6eb9b98c8b8504d2a740934f5e4db53493bdc94b78fa0de4bb4ce6b0558a790ab0e76462b8e0a4d1f0ea26977ffb8ed752c608a489f6211e647213aad1e05df39c210efa3d2cf0ce4112ef95fddf79eae7727546c1fc0ea3be97870a560db6a87c3732b9a7d9e6c3ab39a6ab7e299bcf2abc3cfde88d144fc9c553b944e67632f9d351be79ca5745450576a64ffd9b43bc0c7b8f5695630a55497f433c9c3b5e3c09032bbb7379118555cd6e3fe0000ffa30ccb1a2f0dc5d6c8aea7254d6f7409b0fd8dc82f5bec84375e61326ba2afc9a101941227dd65d68dc595b3960576a71d9bf4d3f18914fd43972c0a82aedd38753ee4051c0c76d9df6534fdaed08d58f96179f4f71f898e9b5c04d48be06a59fd9c61818f098341fa17b7f6cf4e3f8673201945c5dfbf6c2e92da591867a79c077319f74303761a71a273838dce8df3165f635cdfa1a8f70320472cb0c6dcfb082d4d1ebefec48b4cf9ff55ce85b9b67be47118970b854eff2c320d9b0f18c72f8f6b7b5a399bffad51197d03de310e45b1002f6400028aa5fc35a4a8a12a55e7bc6da1ec2b9e7aafa58e5b6b9faaeecdd1c21e407165af29e533a43ba16b303cf8ccd8cbf210fba9c8a334cb7fdff37020347cc347e0c3bd849dffcfce8f41c3bf9aae66f65ed21b2b7310a08aa1c0f7015b7a1f1618dd10f9686542cf87815f422505423a26a7ed2ec3d0a468e57c045e6a9847839fa7bfe492127ecf9054e0d6d8fb22769c0025ba227d24758503c538e67a25ca337b5ae8ff7a77e34f4b54f8b6fe791c2b3e5bffcefff016026985ae1330000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/stress/64kb-32 b/cmd/precise-code-intel-api-server/testdata/filters/stress/64kb-32 new file mode 100644 index 00000000000..984313fcd93 --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/stress/64kb-32 @@ -0,0 +1 @@ +1f8b08000000000000136d5b4bae24496ebc4bafe301feffe80082ee20683133102041506b31d32b4177979991748fa81914ba2a3b3332c29d4e1a8d46e6fffef6fb1ffffd2f7ffaeb7ffcf31fbfffe56ffff93fbffff5b77faae5f9edcf7ffce5bffefd6ff89f7f4dcfe8bd8e07ffad59f62e4fef73b5b25b7b7a4bbded5cd253c66a6395b21e5c3f73c29be55979e3a35e67aef86b3cb5f651d65a4fabbde0c29636df5c798cb49e92f6cc783ff7965b1abc2cd78abf76ab85779d7bf0f17954fcbd5259cdbf34f693dbc4f39f9f92722da3f3b96d94599e9af25ef8339e9cd3ac29d9a3f97ab6bc4ac377f8e555076e976b2b794e6c23e3797ac167b78c173ff19d3c9ea1afe5ba06ac82bbe163dca3e3ebd808ec3177df1d0feaa5d5d49e3c371e84d50c2c6ca6866fc8a03bb5d668b2bcb04719b1c2a0dae3e2556739bd2cbc835df79af0cccd1bd8b924fca9b927ec59965f0b8b4b7a32cf652e7cf5c197d748db8c8905711d23b57536df076d8973c2496025abe3b87431deff2ca496a91d63813cbbda9a9d785e896fe39efa6ae99bc7a37fb11eec0dbe516004d875b79cf106d7d112f60c53155c99605b5b319e060f7bb0989e3b5ec0f02da526dfa317261e6f1ed82b96be323c66cebc2b9e6826c449ba0969087e6363616e84a5a5cc761c6ec9903c05ed8d4fc343534af9dab3a58a154d3cf6e32d29c995b82d6c9c6f9551e8750b2eaf4318706f7eb8070facecdc86ac59b1707cfbba5ce58a1f5f72cb69f4d5c753ba1df3e473b0ec754e9057ca8ef6f85acbe25ee1200967c8e32f3b31e27ac3c31f1c766abde27a58616fad78a78eb5562ed43c8feea4ddd79d65083b4c1a058ebd3b8d9873ebf05a0562c195bc109b4d7ad167e9707b1d380d35100675d0483f88ea5a0002356b6ddcc9c02a70eca59f5de0c8080e051b9e089a54f16ddc0af7cf0a273c9c4e4a7fc15b85069c79d1f30935cfb56c3e6862e7357ba325375654f2383b33f3c0f4e7c5a02d5b5770e28c3b0f839ec3d5217071aff20a063cf06efe380b7c20b7e60ff1d8cbe6b02397a9988d63e4deb1d495b11a6c29cd58f12a340ff691690a863077e8976b67820422436b99c13a0c87dc1f606200a16f9158ad55af69a044fbc79e9b3cffe0ac3da7f0d0b017fddfca6bc3ff3b0dd717f1cffc1e3e4a576b38d4c41d77e126f73f78adb918b202ce09ef4ebc1e669883bd05372484e4d16e4012c501ef70c8f5bdd83ec66af15cdba796877dc917b8a1a5543561c1ba959660c56b6d3c0efe26bceaa9d680d09fd7d120a6078276d897144a098e407f2f23c5deb0197e1dcbe673151b08f893c1ee9a93bed5e9736309071e0bd5814bb01afa90d2a4b05326c78d4be24157849a799927860e4f40fac2ee78c44c388e295dce2373f11b2392da9845370c2f7f0469b36f3c496ed978908c6ff8c4ba26a45fd3326de5117064e0c063e84b61c22d8d960ed0164638f2b6d68bc7af1756b6c81bd83b4da050ce3b67c22200042ba91ec4747918190e0acfe94388ccdcdfeddc482d7003c0e8ce8be809e763c4c3f80dc1c93bf70e7f05483d3f1b2b9bbd2babf058cc5e453836c409ee495954338780d5c07011c65837b0a7eee601ceaf59325b4cc70bf938d8c0c659e0f8b953601d5647f89673d1b84959ff0d36af358cc46bc38122599230d524370aa0930f25b12a9cad80a195d9bf5ec78ce52eef07cdd32af8830c81e7305071030229a0f24b812cc5f19c149889f10373973db4e23917df3960674f65c0be40d43eecd83f1317169869bf5e94802a91e9c95ba40fdf01abcc23127bbe891bec8a8400d702bdf724f2228b0d50c937d3412c0c302264c888c9b49879c83eb0d90da7c355eebe8862f156391a8dad6460b08b00cb1d78e55edd0c4b2756879369c6552d0e2717e93c81f74dafc0b7bc12aba3dfd5c7ada4834d2d109a3823ec031af03b2ffb25cff97c7c1b9d97e3f1e64e3cf99db62146c78b5e8c39f6c4779f37bb008c94e308888d5e3c0c927bb6b8210c5a3c560bc336e2d643cec8bf20004e69c8cf4f875164b82ab72f6a460c79c584234859114a878059440b9b44b96adfb912eadc70c210b729fc28316b051a86c39de895eff129e70a4472511cc08834144d255fbf07c500c0f290e199517713a37ce55f8489515b180f91671c14e09b5e809797ac0167aadac786a7c3b6f99ce4b86cadc9939c20d37f79014070367cc2e42fffb2cc1c885b2c257a72c05601e8e553a370bd7b30c30859a65848a91bb817f7c8b68855220f2024c30a0ebb6e46068f5601d6800ccc722e8a25330c4d3051b2a4202364b780ef62c51bc30e2409a00da3a3eec21f786f3bd46c20b88dea192ffad45aabf3b65e2e9d40f06cdb97d3f82c92d90024bb9780aa002e0b6aa022c8a23ce8c772392c948e175d98f92128a5cdf2f51c9323df12402d56652b674f3cceed9cb0d0f873cf394e6e1e9fbb9c126192ce323d11d2991270480050b9be993b797d536dd5809e60682f4c5c9b57142ba62b13995cd84e00eb1b642a4041a404467032d0699ee1b532d5f086f9e94bab782dc1b56edb5206d32f7366c3ab14873782660c555c65ff23c273d76cc9da5dbb1d6725f3a40fa90c9606a0ac06e4cd2c87457149521aa9954058240b4748f8935a40ef71f0325b2b48dca196a82d2814cde539c4cb2c634a055f840db32d2cbd8b662b8bdf19c79d54145568d722d403cb12ff96a0e128c710ebcabc4d8913ef91f780a33a2f434a4ff63c929984936195a30c0a56087ec20d3ccd05024f555bc7614f88020ace489ea4fcba02aae9ff5442c0f5f16de3ef67ad4e2f442441973630c94e4c451b536403766cd65651425a9c5859abc0ec2a34fa2a3adb4f9da79528ffc1c573946545156091fe11f88e9d371d323338727452b23ca144269694628c981bde32a17919706e210522a83aeda354ea8835006b16f737739bf1de8eaa8b8798444554cb9d27cc6035997c4ac543579c1c6da7ac59897ab81570d66283cc124196f2aa0141b3c2cec36bf9bbc31fb251c40553bfce674a0060593b2564199f7482922d28d226f731074c27bfeed80bead6c1fadb6ec88880f94bf54dd26e91da8b6209f54e01019cb4dfb2206ba1df318ce0f2cc998c97c2f59946e325e810c28c99449591619ae1d3b1aa601ec9a619bb310067e5e25efcaa97e36c5ef57855a663f466933324173de9c5c2171e2336ce0d0ddbe44929351b08c91ee075abad93c77895a480e72bb199a879b211116b15550d4c449bfed5a49a05d2afa8eae1f4df3c7a7777249864d5fb23104f9425cd14db7c712982ced5618aacc219a53c51068ed3dac9be66122e250b1f413e7a5acfc97a2a7a92f49451253f1a00d0e1e05a236a9e95d6d52cb0856e19fd3cd6a8785381c87c8ed0168c7cb688a2b1ed636161653ef1bb7764c5b657bfcaa23d0eb6c07e07ef74c53a7c50c31cf41123f78e642a7fb66942280804b7ff3007f58500ddcc543d0892c25c729cafc8b27da586f05a382bc73944c6a9f070c5514bc95cd2152ae2e1f5b4101a5e48cb1a639908f083cc891279d1d171e3568a697d88a17a2a07d3826618f2551404601865f82101ce149e949e6b314547c93178a42365ac6a1853bd45d19b1f99d39316e15a3892010dce62b26493c6d55ca1637999bd8a2b4e0b9dbd6442003e9933891f593d998d91c3a9e8715d1cee571a26628d75e234196d5a3e96c26abd2fc70c2b6604540b698a28669a3522279be48df3b7da2968150e6af6e0318b9ab89ed2726031d95d2e12f94b56aa383e403d45f9a4e5d482abb9384015f553101f4884db5695e32f2c8a57212948a41e967a0874460a022bd630bc64db244b9eda4c39a384e0e559647d6f7d68a8c52c9192b2b54c41593a9d8ba625a9d42e45ea16fc56d0da7daba0de527e700f466079b1c7f5b8b87544ec88e0e1bee25bb2f5c068408a000e561ae91799e8be8ef8040c6dc95638332b5678a839876c971ad78e44052f6009c5a807b72c565b8f582cbcc6a29c34186fd7a8620af13d1ecb4fe1d392540ab5a22a6831118ee6b88e7ba44b5ca2fbeb26882e25003674425a90bcfa6938a94965aa13b51c253cfc1fc30615e7450f1e97f591bea5f4723251b2d51d43e1d6c65089d1737bd5cf78ffe23bf85e7b2508f00a79983a075b181ffcd1102e19822a9d65018581e8e92359abefe8a230483eac1cc96879d2a3d025858b38375308af8e06de7348699dfa98f414d12fdad4ec1452a40b099586e51440589102aafad971b32a51719a5c5a364f838348ccb002f2453cc8b60cecd3df9771aaadd5cd0a8a877228c9d437fe80605852b244639a3bbb08b0a942104b02a649390fb9dfe5b00337755340317528fdca8e9a3932b04175cd8d763a8e2c12aafe56e2a46c1177173e5d352dba5ca036d82643b6a995996cebcd607d90dedf8487580348b3ba0c2647ab533891b60b2bdd4c75440fd359b29fefda9ba2cb6467f8eceede9f679bbc5361248287ab373cdbba0fcf84fcb09aebe23835a97744673cb8ab6dfa2a6eddbe6d9d4749bbf608bfa72dafb38479253adc66257605b45e2b540ff299187e0ec25ab826a097db3cf33eec2f34b3b8fe6fecea2e57121633369c29499ca1d25d93c5903aec2460ec90f7c09be1aa1bc8c836ab572fdeefda8ed8182ebb4c1b36e8201d982a5d4a0842c8ddc6b1c103a6151f458214552820021d792e1365afd82c401da997cdf25e4992e0c0c5151571b1d557fb49558f2a1b35cfbd9f1a1479b92683124b72dccfa680a1e6b8e9dae5398e41c7556b67a9050bdcecde855d6f6d95dde53608e6d840f7babd7bec834719cc4feb322a87b12dfed6b755e1a9e5041813dd5d70d575586ac0d38b87b2949f0202236f084aa397e2ceae8b01a99b1c9eb51ddbfc4b6ea262c41e0ea6f86e0f3aeabeb4e9a6748f6da02eaba75bbe7c60c164fde0d14d7e06c3921a68c7ac0aa8229940e9fd31f5fc373bb15998fd449667f9fed0a5b43b1b8408304bde390810adfb45662b15e499d7cba70578a88566f4823d814d0a858c1a1439a3d022def2eb2a240a655a665fb7f8646426b5479a3539b84ed47a479c21c943fee98197041bfe03605b5d72caab2809022d4dca3be8a70ff9fc3a0c40d7ae525418e29687bd4e59ce1f8f0e0cf73df31b149bd474b33f57e96483671b8816b05c1eceb086431e9edc32e0a228ee5f7cf312f210fcf629f0ec8090aff6983e93601cc7f12ab393b0c7c9273a48fd831c1ec31155908b7d09a70beb3ea66c70755486da9db308eff2c04ee4e68d8a91d969b63edeb5cd6dc0febce0f0f5f2565ec50a80223a5818ee99c0f416bc6c846084291999147acdab9a6adb661151293cadb92e8a448d4c45d57175b07c1eaa48fba767d8f249bc3e04a4b6044123f8036249e457b34fc3849f49d64534ae9a8c993afcb13996d1561cb116ba9b514b04be5ad06724c66c6c695110e4c767cd0b7096c866e045b715184bb7c61403ca381ca9b57a7da264093409dceb11cf13c0222e0dab5477351fef817566f2411260723b3ec3092dab187854ccd8493502d2cbace55d5df888cd164d00222e4bd51f4d7dd4afc26cea874d88c19b512b9677fbd00a537c995948bdce2e724e1743a413cf2398484bfb36143b94c0ba47a6c55bc77832fb844cd724c80063a43c9934b694549086d74bb821c3d2939dcee8fd314f41226773754dda875c74d8f0439d3e277272fcbedd61adc3c4c43eacf58bf5266b04186c33695b111a0a1a20bac9db749376b41f756885b83fc492cd89a0fc8cf6b1a808a38de3dc19afd3158a9262a80d4fde40943d80b4bd671df25eb7b127362798774eade67e1f81aefc117defb7728a4dae6c9a4fb4bc0041bcc325a6a4090d71b2efaccdbae06abb72aa65336c217cddf91b81ba6ffdf4bfe646c6f4569af9a7238d620758370e7d953eb73e701623363429f145b7eed478a33380bbd7745619d338398a3f92af657c7454693ff87cd845d1a8ac1c7fa2be8100dd69bd8071352fbf7c3e50a16a9937579b1a3a9e4a86ed2343c418efe1a170a5d1b8c9a58680d40224a1f6bc79bf2403e19b3d662b812afed5a7e22311b60c459c1b950f098b511352b3e7c935505fbcc534f808b078ba631d51cde886469aa299479c09d669dd7378577a8d4dda244e0d2a8a34bf72a05c0a8dc3bbf456890ae3cf21cee70e90edb7af4cf71592afa1be2992e170ed6a8d6dc3932b141cc7bd48bcab1d479912787a399422936d73cfa281d1e3eeb392452f6be6b196db60f846e86afe0e4e856a161cc08e7516633dc6357c2a8393bdc5a591f40e17339ab525b25d9b4c3a3d1a00d20e483779ffb36cf6e035b3f62ac0383fcc313291da7ab9793a89a15b3fb95d42695e3a43ab8926ad372bea4ade9d3675c2433fda12e15aa7b171063113e047f332c9275192ee583bc759631486cdcee1bd1c386e59a7cb3e6d40534b90784b5d473a081b235a83b14bac7b7ad63e318cb86caceb0bc108c7c13d599333cea969068a49dadd71259f19b2620834255fa6e6783b8e232bf7d87854f6de83c9bced72cfd177734e638d5ca08eb411f5e3a2b6788bb4e985795d6d2154a3440ee379cc564d1918345bf3b90fab30a33f12927a34df326b0ae36b310d49447675f78cd9d9fc6cda9e6a429b882244b23455fdc9b69b5081b36526eabc04d3e603de599abd4c46617a2290946b83699cde25027d867cd9ee54f7c8aaaf435888b9449b48c4ad515ad6c7da81d1613dce9535ef6a22f369f2bb1a957c689398c0a40824b0d164cd850deb4bb13d18fd2eb1792c7da79262ec7ead79abf13bf199ce5cf44d66b4d2d6d4787e917ff65e98754bfbb245afb09322844a9546b6ac46bfca9b1dae320c16ae5b4791243defc9b73521d12a6b909553c91d374acae5d9a62e6d9aa89623e1e03406cea0cfc3ec3902787ae8771e04f4cdf4c222ed26a0b37333d9bc4f55d16b34325affaa5c97da80ecf91445ef7bfe72ac9bfb5f0a8658a5eb7aa8525d5688a6286e23d6e0a6f70c7248201eafa40bc4a0c7e90716359798f959569372f446f9089ea4aa18ceded43556efe7cd5a6c4e7cd8ef1c384ddf54882d332f302a4765cc6d4472f45a582ca90b6985daa70e5468a9fdec60b4dee5c84a44e9a136a3da995302f3ab5d8e12467d4a8e3fccf4ebd0211ed36dd6b4b3b32273aac6b8c3406edf4b104fc14d593b8b131c46707a0ce9f66ab89861bc0e7121d8bee0fd1d40c8e5c8373c524ad9f629e1f30151bf6d0c9667de9875e5c235f35a53711495072b2d33b4a7f7839130bbb0e71acc26cceb09d93ea78fdd7a0ba01aef87d3c7af21c861a8dcadfb63823edeeefe992b1f3623cb9adea2b6be77dd4debd003390f04a23d4c8079cd66b4ce61d83d7c604d5b613dce0f2fb0fb08a3753f6d7af4471369e5971eeddfc35554e299bf1bb22c4017d6cc8977f9e14bf30e6eb718100314f44764f2cdbbdfa31e56f48cb7fe6d9519c04c1a4fafdd71c81aa3cc3d1fb9f2362bd2fdf1d267e49b429dd525642c36ef28ea17a38cce14437b89d95e0e867f38d799f5c53b388c97f6b03ef062f3d21a310b2dfcfc104a7903c1bf2ff456709afd2257ba2dfc6fed110a496626e14f7ce07014b4cb1d7b74a4baf36ec38ad171f5bee642bd719e18b4bd5e4e5f16c0fb9acaf9c1c2e5dd670a3c4686406d1176f5dd69b0df5ee8f746f0d828beadc4d8cb9c8a55db03ec61dfc42b4049b1c2759783e28705f759c84fbda44f5d61cc8b7dc062e36656460cb69eec44bfbf2378a958dedb470869c80df0a3df13ed43f5389115348e67b19478ee149acfd2bcee7f6b14def90c151224b56f76a3804de54c892195c0fb5ed360d618bbf5f799fa6d9a67bbbfa53a75b315894a4ec9ebb49ed26ba240d5870692bd864c2167b4b92c839c9fcb781dcadf8369f4973fc8c8f3352ab44da7de560951012107df582012df9d2d319d64a5005f3c7c27694b2c6e6c3e898d269fcba6eed55cdc2bec1e89989348019ac8ff3ca7713c8a354a77f7582d940e0d30ea47856bbd92910f30da2ed741e718720010364abfe6247d6ecd4ba8aea5be280de9594aaeb7efe53a15ccb5387a75a03c8044d3aee0603e2ad598bd6de6fed0995796f46879a7b99b5c795d0cec918265b6b7091e54b18f6b74cf0daf868f4ffb81af7b413ed97ffc400b56ce50e9feee3a16ba95f9fab7fffb7fcd2dac428b3a0000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/stress/96kb-08 b/cmd/precise-code-intel-api-server/testdata/filters/stress/96kb-08 new file mode 100644 index 00000000000..7a1e3e65fed --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/stress/96kb-08 @@ -0,0 +1 @@ +1f8b08000000000000137d5a49aee4b811bd4badf3036470940f60f80e8617dd0d03360c9717ddb5327c777388995421173f5312c988172f46fdff7efbfee3df7ff9e5f77ffcf9c7f7dffef8e77fbefffeed4ffdf3edd71fbffdebef7f8cef7f85523f013f507b4e25ab2bf449a9949c13ac1ff11343eea5edc70a64e81d9f8b0f7c7aeabd866ed7c32787a77ee6d52f88313df0409c1bb4d8a1dd8e5c8bce8bf489a1a596c7e2ac2ea22c747689c05bb5daa7e0f55352ed2d3c786baa5c3b8c5d6a8b61082edb418598e5678600f9d97242785a2cd03f393e398579712fefef40c63444c643c78d01e153036f850fb110ea690fcad2441960a3a170100d270011859cf7e51b6c057358f6c80d209671637dcf3dd5dcb5feb10e9bf26a7f3803c6aa402ac3c0e71335db05042d6ebcc40d591b196ec41828b53c45376adf59b245154ec2b8326f78c0e78fcd9b45d473ab3eb95dcb00d7a0e478b81f10a4d44dbdca318c909b000c2f2be940171f5db2ed33c2c95862c7e0de84763bedb8af0ca39e358efbea5c73f9c2cb1295034285276aa22f6e4367da6431bbe2749e9e085e145472ff31d476bee85d82ec8ac655c0dc3cf162e0030b091d7c0219752d777be0cf6b505a8b6b565b2e95180d3267f626cdb478514fb1d05eb984dbdb0794562fa68f970d6949d4c186b53c64161f107597c09f2fb50c6a1605249c4466ce6162937fced8c8d2c563e919adb69390d8f8141f1c2d37d0ad45c765eab5699f0fb7367cba7faed98aadc4cbd7154366fc412490cfc5bb279493e26899d4624ae399a534a9a93782506efa13020743d04b6c86ecb9e42921e252db481a62bcadc2f2b18a70ccbc2e89c641bacf587e8a66ec9e0229431cbbb03dd6b79260eaad93e800ae3a3ac6f084129f99421864724d4d1a96532ccc36836b2da24c45104e9f1e40ae0837777f89a5bc5a8270855ae6c39c26b6ca03d474267da63e6d3023e7c4cff8c495394b41c81359c7eabd01b38057983d7799023a37ae3b063ded25c4514412e3880a95477cdc39b1ad00ad4969938dcd9cf7187109bd947ec247573e097ac06b368643886918e6a178c74a327520b03b5a7fa5f2568bb304994170065bf17a4f6f1b8c5eb863b3d15948e099bcb5f5e02d8f4401027704a344158387e388b103c09a8a75fb9fe464c7c885d685370eae83c1ea096006c2126c09be2d658dbf53c04faa9bb185e69ac0a6331f42b842730d42a919ef1bb0469f335c44281d0cf68a87d682c55cd7a417a148b76c746284c6a20758be5bb963a9ba6b0f9d8a294ec6670459bbbbe54d46f4fa2eb8f8284a86fe2866d170bdd1e6656fe78d8bb3f5faa2d32419c5a3489265e71df2d15ee0259378c04ce7d8b7d63d637fb5ca02fbd22290a332c52b9670d73ee574d2045b73efe028a24eaa676313af7e2f82712424d9ed433663dfb8b49b40d64e88b37e2ec15d10560ebf33bec0505ac8a3cfa1fe52f17112ea632a5c3ee925e3614b7cb7c86b03a0196182451dfe54c3b1dd50a60f43c844617ac28252b1c19eb69476fc76419060c77832226c6ddb0b85ef120ba4d25adc428cfc4463a1c52a495459f0b56563becbec2722610b45c2ee235b09f70ef6f659aab29ab6ccb63b78ba8e27210e34a8ceafcfb8807661dbf3970dd0eec636960ab3bb27d818c2767bcb7caa2ce58539ae605b25f2b3aadbf99745231c1230b0afb9fea7f3aeedc46862652f1bb528da7105a81dd24e7f8c33755bd1ef68720622751fa14939b4dec040c79119cfc3cd8dde948037b03c28588f2c63e8a37b2da12d0a3bfe4454a4851eabcb036aeac51241e80ef213bdd87bcb09ab03e50d29d491c3d61028ebf5537b15232ceb15758c631d78cbc7b4f72896a978317674b693a1c62aece3a8f9413aacbd5b3aac7e679739657e5953a90fba89adcc511be741285387a0bb1cbeadb9c29aea9610ed6a392d65bf1ae61572c378b6ae69b4a9fde918e63084ca84e0544461639b668ab316207c0443a98d735d6502a2ba2f41904634b3de671c036a23568960828032dede25cd69444b12b2cef44769dc90331c7d8990d16f81e31dca2022eeea3873acbaf9d1befefe82e11eade77b8279d44ba361267db71d90e52644159b25ad55a090d773ab3e59e9828e79df318b2e4622da548118bb486f0a008dba0c8dc135e26f4d56bddbf7e5e94d5af24df622f1c03d9af9491149b0f69738c08673f7d4bb9151dd8c1f81da1a48a91a2653ab70b4f3db4e8a4a65cb50a5b2ba30f8bc060e323197290875fb66742b31c977aeb12c4369a7b862b096004167ef6cbdac3bc63d86465ff335481c9efcc0b9bd1d80f0e899de40f02c47f7b8164e0d812b48d54f379a880a2f3f3a217265ada5bee4f29f2cda53fa54430243a01e1b4dd47be859e7ce8f1459c61d0d4c1ba4dbac88261912e37f9214f148356e3f6efa224977e9e7547785aa270c1fb3bc82d2b6dcea25c9d19229628f08ac1041ef987a3c8a292c8aa9374471fda28443c8116ec59da56df0eee90a9ac58f366af914918394df02f6785ea14d36cdd9f1bd1d6adb29aeaee699c1ca63c034afc325ca286668e8821c7603769cd24d31f53868efc42f20c4a7f9ad95ab0ea6a0cc45418bf674e3a9d872b0cd9aa28c38e0611abc5758537ec2184412ddd17cbcbd71396a200d8671344f0532cb51e3a6a4eb2fd58d14ca012e46f054bd3b01e81015688e199bf797d433d90e6442313e67be9379d5e6a32db507a31f7e073cdfa19b83fc1c78e7d4f5c7a48057a0f5ef0521e378eb57f56ee79b1e5c8ab04a274a24331e6a729e9ad408537d40f2958d9ae2902135bddc4cd90d26d62b8e79c8ae7247e5ae90bd0cdcac6ece551443b5d0d9af36421bd2ce9f5b20ac8b467c5623af73687c7ba7a65117d6c61a472f0954a6efe34632d649ee98f970241b34cecfec42e36578765483d3e973bfcf06c96792bf84d647b3cc7ae77d10a0e33ad2a55c8af5fd127c4dd2c55585bcc7b41ed337327acedeca8e9096f026f40c51ce2694074546e097016e4e2f15ad69446f2ff9ed87a82dc446937c19db233975c6abf83f2acf54403632ef147c513b901965f5f966c9563536eeb084bb613cfe8fe59e8a105a15676e45f71e05ef3ab25d9f61b5f4a1ebbf7fd05444a1754d149d6fd2ee67b2e79b7fd3221147a341035daf10a08029c708a6bad3ffffa4668262c075a6cc6654bedb6a943c1e2ddcea6d0fb9bee3e3a5ee4d2739d5d77c3739a4ec739e9ccf41e16a342afa17d95d5eb68b21d53f65e8ab263444d21e824f0c3288336157875854859b596917a8189e523d6e744afcd79e1efef6bfff038d9186fabe280000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/stress/96kb-16 b/cmd/precise-code-intel-api-server/testdata/filters/stress/96kb-16 new file mode 100644 index 00000000000..d18aca0cc1e --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/stress/96kb-16 @@ -0,0 +1 @@ +1f8b0800000000000013755b49ce245711be8bd7d9d29b070e80b80362011612086116c62bc4dd8979c82ad4b2fbffab32df8b39be18fa3f3ffdf2db3ffff0e75ffff6fbdf7ef9f9df7fffd72fbffef4bbba9e9ffef2dbcffff8ebbfe1973fb6b99ede57bd779d67b6d1ce795ab9bbce569ef2b475469f031e2ae94f2dbbef514f1bf0f69c63f4869faea7c257e3cccd2fe403f9cddb9ed3cf59e5e06fedd899f8e428773df8d18f566bbfedb68a276db8692b15b3367f27d0d795c86a5fe3a3a3ded1cb80dfe8f044bbb1d38cf9135ee59f7adb201b3e66228fb3afb3cba507806fa4619d06c7ad5d0b7086e7f6b9669d67e4dbda6a75c067ad9c0142d87ac568a5b3c08b0a4b6f448af9dca344b575c7198544feba00eeeeb7f7816a61298e0d378124512f77811c5c19d5cf86f76a8793ec63f8ab8f56f71605351671dbc4d200fe83f40adc5dd78687abeac065843457d382deaebfb37099ab368a90dc5a9df0a592bfc651d1d17daba3a9b4b69160b5b7469f0fa29c381175a33dc0ad201fe2a34fb0aa25a262d3359a81d283f60977b5e28649ef990c9472e2ab0c51207e080735208679870f96d04ab6574bf01e132d487f0f649b3e3a9bf412d92e64902ecd817e23a65a985a57030bc2bdabad817cb006826d45432d62f1e7d67591f7e0abe612aa6bba6f4d202711f936417fa2c3fba7b7f8044b24f3f8cd499c5af2e2de6697a842f65662e0b197e0d122d797c865be4ebc1a6c043eefb7dcb2489c7ce262ea66835f982013317c352016cddb826ae56af707e267ec4bcf9165888957630923a53a0cb163ccd45126681a4e261f9b95ad888c4fa3a5debc468a0662f787c3c25af0068ae0f6edb68c9cad3b77af4d09e7bf927245c61aaee43afd03ecd0cd6ce7ea02a408b27ffa1f1d1034f0ce24ecf8e8182ba796e2e62d34d1c91cfa7250924bd523c9e1d75dbd85c3f8430e9307fe5b4264516addb7e8bd3542e8afbde1eb161a553a43acebaa490ea5257824fdc809cd3f044a49f6c1a282f9baf3adddfabd745908d8965ad9fece5d1294d4533ba4f192a50921a00d64a25d8a02141e84023af036156ec333c0d630a9a98ccc358f714d1ae51b3d4fb268666d41d36caf2496e7071d04319232e6408968a231ae6ac003c251880c1270e959579afbada8dd9425fa35a739010a981fbedf966b81c10052e852f7a135d47c551a6e19b59d68f5fcb1301acc20387c785e91c6923b0f2af9963397d87ae06db947dab976906631cd9866604c8f07d3d1e685e0a12115451ca80f52ae12f23466e90ff005992d9a7a272385936bef05751794abf20967340874092d32fbb3761618ffaa712225e3c941114483ca5232470a0f67ccc13e25b2010040e033e64cd542c02f6e249cd8c5be054de0d56a3c6c5eac9285e798fd30eac8c16a88254eb8ed9899626c5da29f95fc0d43d62db35e0cb0a64bc5b0c1100cc03107fb3160687e550cebb65a402cee488cdda2cb04dec493251663f203af1e121882d53e6cbb080d2153c00385299417394fd4a0468389963634c401a36b525e004a312b8b10310d949d02bbe9c95c296457a21fbf58230429f7e9f2b6f60687bbbdb741c289650f086396c21069a85d2624c707b93e4a81645422b4a624aeca38e2149ae32cdb26205df1e275f72a25418c806f952bfbe005a85c520c833605e7e85811f4d153206b209c8b3ab25af8247b8edd0242a92b23ca9220c36ae09a931c0b6c1f25a7298a081ea99e224ac8ede14748bf6bdea43af22b4ce5207376481230f3cdf28ca63b2df9a2951234a0af8f5048570307273b04db06fab2c7d14fe81133809a949df73652c621963d6b4a569cda50980701fb0f633d25f2404288ccaa7c01fcf5f68f4a0055a82a3ef800d001590684c121eb089015923a82e83ae19ea5b056f9005df629c131b15e7781c273956884ea63c9df5f02f3146956ef8528aae25566e2f1e5c9805e2d391cad2d004dfe9d23de2129d1f3d14bc6cb61aaea4bd18025af841642d854f91859353b986b2e86204895172a5d8c2360aeedb8d3a33406a715ac1de0274a3c5c8022653d566a4408c22d309f1b3976ec0437f5e90d874f1cd59b113f03daaf2936201bb3109a74d18190fadb240811941229fed64a72c1b6b962e46cded740bea11edf82f42984c85d150816d7c52233389b274c3a668f25848057f52a3d8c79220d39061e48bc682488d705fb68dc16f953f8a720e25e1d029920b488c454f5288949a28ba1342b64a53697a649ed80857bacd8d5de88894111865aa9592ebd7e6b1951feac1d3110adf0b0f3d64b97325842336b9c2425ce2e6da918d08cc2e555c30dc9cfa52e2ef9628b535c17b816fb5825d6ca7b4c720f884b7b6549e626e327946542631c996d78f1346b2054aced2e252cc565957780b241a4d39dfa96c8a478bb76a4b067d00e956a820fa846cacd4a09934725c755f69c536bb8b90bb828360049376ca070c8047180881eb2da27e572cd6fde8618da06b5e422052edbbc719874a3ad950aa6b116250b30f9721134b588e0391326cf0f153fa6e90d36571c4ae80fc05a1f4bcdeddd1cdc087c4fe8f06265f3451521468dd080f368ed458e719252e062d80fdf6d8c451edaad21042741b1b162c2160a56c9ae216a80f0dcef6c45c246ef900a281a7c14c11ea54855dc86b508ac1d20519b051c89c6c402098f9b00647490185625ea99c83d035464f14a0b0dd01790c11de085cde457cc4c899a0bc8026062ed160a654bde20c0e8a63113b126cc2e0fe2512befb5ea4bc9b88fb221bb29f01460595836edb600487394f1f282e17502ae8c4cc4985ab05ee3b483451e0d1a167906a448ba7388f14af7772dcb55dee0506b63ab06159d91c4f1f62febcc7c20a9378ad193436a0c9520dbcac741c27400bb9c7a0db1d2a97d84e860c28f5d190c981ce6be97222ddc913a30e212b10cd7f6147651f360e85b0a3572b286f46b3d58ee89a0916a5b353f099dda6a2576c6db11ce9ae55bd31e2f613807bedc297174ac7bbec4236993dfcef5bdcf338a3c1e4195795b4ee62ce8732094dd65e9982849456e2f0b7007e7957342c64a0775428a56c3981d255149a8536394b787611e735748013700cadcb5d7a7d91610eb398c6a0abc398a6052d2a4654de713ccb076c7e20aa5b95487f293e23357365e100aa34c94a823807a1fb300717dbf1a3fd3eb558ec7663726371a5c68cc78c74a71c593034cb40c6b5e0e6adbf4951c3cf7a9d02bc87153843334462d27399d3a22b17735759219b189e85c8d7d18300ae3252b49b8177e5b223f8d490bc4b57b0eb712c4efb54c6363facc251d0e989c8d20efd7dbef1b25729ba6bcb0b26169a9de42ee097558a0d50ac850e7e19f176c961ebbb6425f334e1e9f98a7d15b868e91b9b5827da188218bd6b619063b2d729d99885c8b45cce187d9b012a6b1c1e82dfaab452e09e8e0f74df3a6c5a197c531ee0f832081c4fe4ce0997fa236d9a8a971529e88a7c23c2087ec7096ec0984e2500d3ace7d4dbf1f598e278f3a337917124c0fff05be38a9f4614db1f4ca1b74645b9006e656ca56c3cea48db4d740c2331eed7585396dec6ef8aa8177c2c1bbcf7257483172d9a42f58b8f7d0bd07e0195b719e437a9e6fb22668d343da601ca969041fcc20572e70daead388f9ace32b5af45dd4a508bfda13b1d6a0de1c9bb643b8852de603fa3a7158a6e125f5656d584827b95454105c02a421766d4f9e608aa5c687b442771fe6061148b474ec03b0cd359af1c7658653ade2a35641def80801b504f0ceb6153c44860a6b39de09a5031588e709b9497540d5074e9a774b8d25ddaa484aa52240ab943866e88a5eeac1698721dc18557da72685f8da9fb037115266bf3d22349dca52a1616515fcc55b19dedce5540048a0e9ee436c1ee1681e737f8548785b74d7dc9dc56b3e47fe0e14466b1a3ea8a9c813b738b096eeae4fad62cca1b6445f7760f45ba9656fa631534ff3d52c8e79cfc4ddbd9d6313d93d4a84695ab6a5e50b9e514f099286c8ca139666749768544aa7879db301a4e82f5c5ec4aab7307dca19c3b3460c2f2475700aecff1365797d23e07b99e44975de72128a312620526bf214e9c9bec60fb9ae9021b73c13ba7f054c2dc0a48fe0c500671eef018408ad900120fcca398861ea2d50814f3ed903419b9715ca3e200c64bc96c298d7baa0c74fe60c07536fe704e2df8b40febb0d22332cd158a3b5a436565355fda5dd6003ff0fc11b5760ed678e622e2b8ac51fa989c8adc321cf09b4c2f0296d622a5fbaf6608c45b39dfe2e851b2337c9ca5aaceba83eecdae85a0cfcf0dac87be505456b510070904cb4251d05ac623323cedabaf2575c0459ddb1d316d70bdad0fd3a5d408a5da839ebb96de59d29f36dce1b6cb51f430ce018087fc22a1513ff237208f2ededd5852371ec6b0d15ab7cbe35f13715fa7954f99a625a153b2d85fb2cd91cbb6b17869519f728c4fb34be7f5b5bcc170d5b8ce238408c698a0ecaf8124cbed4b99f2b16629d54d4dbdbd30c567710dd3d68c10f4365e83ebb23ba0503eabd94ddb2badfc36ba64c198a189bf4653b74b10d241b57d934395375428518d118ee841459682fe77ee9d0e9c2460b82e5cf14cbfbc61ac67ee108373d53959eba02af0122098c9ae5f7d1c1791204ab2f3432d2064503e63628863b7c078bfddb9a0b41d7293455e9075c5538300c57c63e7fd852b3581e7af431ee1ada0cd13035fffe4f6daf7d02da268b3e9a130a79e19165eb77732ca2573b778c54e484b16b5cc6e4853ea43d656584890fcfb1e7b91f7e4300e3a549ea61d0a264969747f9e0bae69b79b8330cbedab47e45f70cbd85f139f391f4839a65748c3d2708866743223fd52a503097009dde28a784893379f6ee85d6959391b4c707eaef50209dc550ff574bca00eaf70c73fff708611b28b736739735d218fc437c072c5d1b36e13595d2dba879e0398cc6640e97b0e5722c0eb97d97e195a8cc3ed7097261b805ea7a724334b49db399bc46ab60dd88636bdc2c7977ec5b68922866e68c835be1a98b15e61f82045491067c8497e67b7e2b221957f84ba86a1dc0818fb15ada37f0ce71d8b5262fa62aebb37f6fb503ef9cf12e49b3073e1b64b49244a6174514c8fc52033d29d8fe9f15e92f08709679715d8117a57802174cd88b9fa5859b6407afddcba4054f8f04b868346ec1addcaf9d8c894bd857bd0154b2768ff336c25135cf8435e085a1912e68c72eacb4d35e98299c92a55d1f9fbeefb37803c2d3c047fe28ae6db6a64af5146ebff6b225b2855b1215dcb1606c34b86f4927d1e7f10e9a6d95b7443efccc3780751d37566e4a0a37ab13eaa9d62de8b89e321844589df35a80b758a7cd48330ea2e45aeb06a4bcdafaba9ab6a81d0fe22a6b6a1213a6a8ce1eafe5e6f7ce6b791bb2648b36d8857fd4bbef3c0559e1d5c5404c08ba3c0fe5c0e21dd9a68d14d09906acd7f44adb96f4a54d75ed91449bf8b0fd5b13edb7f0ceb84d963805fb1a0175728b4ecbf23f4a092d05dbb08007f41fc2843e8506290b7562cf7ffaefff00ed6f7a7835360000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/stress/96kb-24 b/cmd/precise-code-intel-api-server/testdata/filters/stress/96kb-24 new file mode 100644 index 00000000000..9d6bb78c052 --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/stress/96kb-24 @@ -0,0 +1 @@ +1f8b0800000000000013755c49ae6d476edc8bc6f703d9375e80e13d181ed80503360ccb832a8d0adebb833df33e195fd27fef36e76432c96030c8a3bffff6fb1ffffd4ffffad7fff8c73f7effcbdffef37f7effeb6fffd0c6e7b77ffbe32ffff5ef7fc32fffdce6faf4beeabdeb7c661bed9c4f2b77d7d9caa7ceddce1a9fb6cee873e0a3e5f953cbee7bd4834bf63ee718bde1b3ad8e4197ea052fe333e36cfc449f7faedf3ff8f8ec7b7d6a1fad6edcea536ffb9c7ece2a872edf8edf8abe37ca5d9ff339e5f3abd5da6fbbadd2923656b06575b5634ded53d7b9b2587c60f68515dcda9e7dcc71f29aaadf69d0cd47bdbc9b22377db65acc40efcbb45abb986ca89bbd26eeddeb206be23737556f7bc9ad7aabef4af12959ee3a0dd75ebb96432781d7e79a759e916fcddf9b05eb56ebd756ce8021c914a589f1fbde735f5e3596798a6f43975068b5722358185fc63ad81ea5ef52f7e29f5f3b6041fdf63ee8f8f1eb2f7d73ae45c77e178e3d4cc5f6f68d9c39dbac5d4ea8e9d9991bb4b51b6f96dee00380a978cbe64b936dc42e4257d8f85a5df64ab2237d8e0fe5ea266345f63b2f1aee03d7a36bc282a3b0878ddd5a9df804ff0c73aee10616d7eae494ad6d5c81d736e1cc8d5f1ffe3b3cb21575233d0b76d24e0b8119d9b9fb2a9d8d4dff55ff5862e035b11bdec7a1e8c0fd5b11cfd5980aeffea829b0587a5bf7475fa55bc9b72300f87d5cba61a1729556e48bad96153000fb5148a6688c83c271ee41e6e297e083b4866caee42e27160bb38c45fe2ee152646b11f8822d72d6f62a7fb522b0b1894126a07d55f5115b6a8a13bf5953afbb971607af5ef4137d63ad07967096b8f69223d13589f59f1d758451af9b1dd0cf873ed17191d3db8309ec0af9ebdf4822ee649b842bcdde96ee6ee39ac396a3be1338eb8185435dd84ce1a828ba20da74c7b6d99e5f0b68972fd46469fd96cbe7cd175f6d4dd90ee2730e59a4ee4316823d0f20eebc4d6320ed433e134b236b54385a6178668fa33433b14d5e897f14cee051cc3bf57dd65126dcfb10ca353ab9c981aea841df270828be163d4c818f75c7017e35cb0beafffc269d0eed959ce3f67de2d0c9d3c902ebd2497b4a93bf1ec7d06331d43d92324a8ab31c18d83bdf595cb98c2f5fe84daf57f44a1cb57b65affecec492422898574eccf60d3e2d8f3280d9bde392bfd116f87ee467b29704bf7a69baae9e34c3176e3ee19f640af30406b64d3f11f8c30e7b33dc8ce3f85312c2304ec9d152e8f03f06e504228d5152ce2a3c99b9046d60d75efad2cc8ead6f3f1bf770760ede1e1fa7fca8e03b97182b9b116be43356739ad7ad9ce6edfcab6cbed289b47e2f2f4e3e3414b108f18b22315110c96c7a02b03cf31d0f178f1efa17d6eb9c9fc5a74108c4b9181b78859a546e579bd5465795f4b69830142535ee578743d2972b0b89f4a9270f0098f5ce991384c07de638b8816478640d662783511b6671c0a6ed4b08a57461a428f115826e7cdc715d72b5e3f54bf03c26dd31d4a5ec166ca1b61e8f5358c9679ad6b27017dcbc64b2c9cb5780464aeb77651fa65892604bb1c5d673ca7572a0aa6557a08af258c4691f6553b6fda46f18175cba12a635173b26bc1c3002d140fc3b2c43466057b2ca5d6dee046141898272297f588a1e0fac6904d553711246cc890bcc0b04b5f82272249c0ad4cd2fac14c50f52579010dd7ec03b4cc008c63b9325fc553ba25b18b8f990457e31df24b06c480429c8ec3c24934fcd778aa4f4866163fea34c73dd72387674cd23a11f2c38e660cbc44d1041a3b0bbcb518663a88301194eec33bfad6058db8bf65a5764f6224edd99dd2f725a77585b467dd6c9bbb5a51fa3ca4893e3a44aa81f439cf555b365db1aadd465e1580af6ab495fc2250e726b0abb6a7e72d2cc789b935d8045bbbd98c7014187c63e7f923e9253f31a4709c46d5ca08c6b9074dced81a26b8c63479142e8238144ec1bc03ab8c8a1cbeb778342be88a5b56a66592d81886106f9d76c46868c25eb81503e1570e265bd8caba47af20781ab4ac1e90ddebf80b3ef5211ea719ec22c08ec6e018929cdec960b81414066f5507298c20413a4829d7b58880447411972f7dd9973d04d2e6325ed689acfb2a118e9388a905c862679e489a2e56b23f6122810f05d13694d516229e9981b0640fb0be2c1804fa9f023d2a4620398d4e6a11ff01e9c54d30b4eab2c3912c9237885370bd67dcc43f2b7f800506457a78cbe204de302b7f0773a412c0c914826262fb46095c0f0e48c30bbd8c08963b67062074124ad6954463ec0fe8e34d1fb6b0704e8b023d7bc54b85cb57caea09ceb11f83f427b0db5bedcda79b46b0a9ed83b6ed5d961b91c1da396ae148cfc38391ae7e04a74ddd62b49919d4a01c62e5f3c40e41cd946ee7ec6540290a621e93c0459bfdc4c5e9e0463a26c1bebe27bde9a8a4af639aa276b8d6d2afa9357d8f98bc5360c39cdfe8d3789548e73ac46fae86e54ef9372865b1c23a9856baa58a8ed76e3fb8d4a2271415cbaaafc834b6c04635fe5672c98a454ecc00b87fc0a1fd1bc020e459e20165542c2c128feaee1a86924443d75540d1430f53ee99316547e36540f20f33681e2ca9b4d74d7e85917c03f9c20c9b5f8423917bd959004897982a3af2a0d5f441d3b050b6e8a8a6657e5a9770f6356b271b9ab6646f78bc7ae8848b83357a9444d54b2d3adabbcc22513e53e3adb692c5f85aa50e8f456c4a5e1ab97f5c1d94ddd7bf4bb0dd020b5ce4293d4d79c113d5539c8dbd767c813d3d2f5f8446d3da254c58627c972267931fdb6dca734300e5773b0d6975afffd908183a95172273c4f99a38dbc4ce2185bc91343a3e20e793deecd4833377b9f0a05a1a47a11567cf16a737242aa9a8c35cb826c5926f3e0e0289638d80747fd99445f282312173769a6f91d94227595245c2314170e7c7206c9d1281951897656760e093bcd05b2a45effd9f12e8d6fcd8a4149347f02a10a024f128e6ef5ae64a3a0a0eeedf92f0f9f80c4749072cc7a2b112d52bc71113e5aee0ab48ea2b49a5e60a20adb27744f169ad98d5210863fbf09e221f271984382f1632baf225049a5dadbcbbdfa4d7cab0b7de198458adeebab687d9a0e5fa58caf36b33ad5d08d3dcc3a3c1e843e21fde94d3299b4b811d5ffad67be94a3f40e152c59ea55c721bb3789678064a3d01e0a4692ee234dd657c4b434603761ee2a9c6e920e20ee8768046490e621c7a8c2362ed999b44849f2c35aa9b84c5a5e6840ed5b91f474fc8943f78245af876cf8a5c48a1bcd060e5c58f03be58251dc66945bb3852854bb832169222513e1fca60af970be0bb04b4294c7250cd08193f48d6f2195e9ed267e971a44809854eedb61f2ea3c8319e8d16f38ae3bae517567caf01650a3daa278a0f0a28d0ed9f2eeeda40ce642122c874275495148259d2f6265d43035807a360b400fb6c29ed69b043b188d16465fca4d9276e950a519837b61e7c6a23952a8bd93ab1724072e546c2b7ae602ad04cdacef688ad93308bd19fbd0ba4f17f8c4b6b020e908d1a1e6f04a915cf7353f91a44361b51c12273c0a266f49d1313bf2ad61e70c0d49c06407f5c28caf460e001ab2eab44ad23406d15ab5fb17bd3fd3806c0741d2a22971b3f2fe447ffac5eb4fca13219b27c59e5660ddb9eea5a0dc70a4b4d7e1ebc7aa952027aa4080a50dee9c90d4503c373023a463b47c34e17fb9ecd37296b8fb63c5ef508657f79ec4513d15a70951081b2efe68b4383debb9bdd7cc0e881c2421e12f04d05b04123da7f253075781cc18d8352141f6d647723712e100b4042994eacb12564ff769bba5aaef9c4fae76320f4d49565dec159bead65fa4e0e002e58b4ca486794a21ee6c5fdcc6ce3b949b33803dec3e38e5511eba4ffb1eb325322c36174793da658caf00051b28c47a82d9442db59eed00753aa74cea4c3988b2789389a776da6e1f99605bf3b5682f28d3580083ea850feb91e83907307c1fbec5d9a1e6fa1bc7b9a9a1aecb090fb41eead3dc204b1f47ba91817d1d14866364d1c0850fbdc67006d94d8ebf6a6ee43753e4bc78cb851031314ffd2e0a124915e0efd6ea11e433092d5d829b52389abb85fe3108adece6bd4584f2d909718e98615949d14e61b48c509fa32f568975aab9641ff399e1c85c28d681fbb0705c57931ef5905ee9a39f5882924b0b1d46a180dacbb014894b8a1289ad28714c947bd5b6e27a9765432ee3fda6c93f69634d82b37e881a2f4e67b9beb54104c5393e12310f15ec14532fdc1b5506e31cde74b0dad04463fe88d5963957a8ebfd52b530c866ee7dccc222337982b48201e170ec539ebd25b6ceabe8a4c85c81347701928bd91bb7fa78a6bec27da4918dc24d92251856bdc2d6494a2c7cdfd4751271238a3983b72f0d5765024de5251d793e215731bc2ace9de1a92931d748d114249bd04e0c9b562aff64bdaddb59862ccd5fbf2e33eb3c0676c2c3227a7b5c0c315ab9420cf022d64364cfd7e0aea8fba5aaf46c1d100169abdf2dbca03b0c3937f401c36d4d7a84fcda260ea0414693c1a808c7296b00928d6230ada8a2534511b5dfad3da605c35afca96ee06123b99345b8cb6c4f4d64957d6eb0bce4c866ccd6331a935d5055b104627225fb78f7904f18a0bdf3291d073ac9446622f3e6593356bf39ef0cd352a87406edf8583ff16438b5f2ab7f79b6742db62c8a2733b8c112352409982203b9a80d2e5563a02f2499680b123f8f111c2f0849c539eb4dee39c748336bb91be52d67255ceff3d5dafac1742c4b72f7bb6cbb996010cf1b30a19e2e47f126970c4e59a1180015e543da29eeb1faf491856f152b61a53452bb3907c3833557d96632b0168d00c6aed245c6d6a18da784678a56d904dadf393482c43563682f464e0e1940bece63148fdc87afa681837c1b39941fdbf15cc6badfd2eaad1de71c8219dccccadd95af11c718521a5cb712060a21411244d6b8ab64f00be66de32b725d1ab4a87f32b6a8bb4bb5a52a785b4944f62feb96fae4d6c89d5b91438e439a285e2c571cc29e28c701770b8b78841ff67c4f101110d9bdd809addc7eca0fd27f9e16baa90f3407b21da762cc549cbbe8104ed7e3b01993afde63a139cba634398d33d45a4f73d90ab8d957678f586be76a58d2732772cff59b94ea5c5b346932c464d42f22811549453818c9132de7f78f895eb9801b0fa360f1c180b3f0802999b4f8246b34b4ef32e53dab0ca2e5810b0c3ab777c4d3dccb0b3eb50b9711546e511ed2a5dc277bc88209bd0f5317708ea3d26a8f7923e9980b95c2e53a57bb41f94db778a5207c68b36e36de292d67f716439c5dbb6c804ff278ad4a59ad18e61e419c06eb8f92c739d554a089a594aa763be588aa4d1d887010a6b5349faa7d0f2cb8116cc9c0ccc86e1542bb0d4fa8acf5d6a59af0dff48bb7f6683100c0762c417cb85d2addb038e5692c2a90e6c924e10dd9d29be875b7dcaee0a9b3bac55a25c4739fd2ff67e3424a5436e207269e2d8f6fabb1283bafe5619bac20baff2d63972937089c6bf30a9e8b65750da9bd1923459aea6db4432fe2b3619ff91d17faa3b43ba29a6395f6a4dd11d36c64232fa363d2965e3da3be2c352651c25d9b724695479e6af44f14c1150392ce677e943c3168ee02838733e5bfe943639c91683468ca981d77527460991f593882b3dce1a522beaf34cf7fdd14eecdfd5b71e299099b4495ba6472ab68c339f7cd3db4a0e9d622971138d6ddd7aa35f4b67726cd46d59ffc586de8493b871a2e59b051de458dc43392410a4be4c111e3910a31f915974b42a464d669996369df58f6d87884f0ca844cb6ce310229c996a7dcdf8417d27362979dbadf3f4a7115f67e65a7d9a4e5aa0c2f4f4cb472d78300b44a2ab2df22f229b5ff6cdc8a742889bc3463127c54ec1432a9f60fa2f944c59675936904c7b484c5b36f0fc77eb48296261469c9972c634cc6624c2bafcfa3ec9799db89bb942633dfc615a271a0e3ccc3ba3b1cd144ac48dad184f1b61d7fd4317944d17265ea583c03f4b64111e412723b66e1c05b9e929432526a9243bd98abf31a163e692ed8ab83c0421a910030af36d7973b46eb2276163d46f511a3984018fcc5820ae7041d509141767504dac0b5b0d2e585b220ee7da502e227a37834d7de6a5ff4d54cd579b69e357c6edeb895a4e7baaf48347f4285d3a340d58ed2a16494991e43613f0cd9f411366d66e2470d10534889b37e987873557d3feda5700a376fff537aec2332cc9b07c0f689d1ddd654c5a4820dbf95afb927af3764f0cc128f934d3e24a222fb70a0bdce3cce31f61b125189b55a7123a7d0939fe439fa541b098e496d1e531ed6ba30623462f0309549c286be503892fc53899420423e7f1c7f029252aee83ad45455abf532429e20fa8aed98e24a43a53e8d42a3dac2198624a579ee1726b0902ae9f549c64271a432198f9d1fbc78e7a3f3a3526fd3dddb35d69e006c64104a52e2487d7e7934822f40b3973ee54c8136b841bca9cb055a580097b75a240f04320fea6c7f38d1e38333d929ccdd7d5463206dd8e33d225cec2e3a841738ef78f555593ccea6853257f5e44ce0ebf6f88ace764c9abc8c01b7e9471c6d28130486e341d367ab78b32513c337284940ec6477e3419c5702a1cc124f73fbabbaa1b55acd08dfa19e6fe87956e4f250cc3a06d0693a757fde562ea068276a624e9234aaf438587e8071cad338e235db6418f9362a57d05a56f06550a07ccc8f11543c1bcc6a284f28b5418342ea588f4ef94d5da2646a4022d14b97753fb5e1edd3fade31f38e3181e4d7235fbe3c5cb6cd6235c3a324a7b9b968ae694c39e610e99c6ffc29a3e061bd5613fab38fb61bc31991157486daeb2413dc7e3610fe9f8a8ca04e2ae457d2fdb8e255be04f17087da9f69584ba2b380f41f4e42d60de441058f1fedb130109cab53610e403a9bce23b0b3ca23a2865ec4dfc62d65f7950acf48f7931e7bbb5381965bd9ddb413d3a9acf49c9f54e37e41f8219e985ab95fed250587afa9ee98e7fe9e17aa415ccb4bc40b27c9fb352ee4d8e1c29ef6db12951587e59e320947a86ba67a47ce8f012c92a279b4b955eee97a5527fd163e654e99f9c6dcbacbfa42956739f2f682c921287833fef091d5921e88697f9dafcfb8b862ceb3aba603bb589ec17f1ad7bc36a12a98a53ddff4442f4177e2093583b63c44babed26532e88f6174929aca3bacf72579720b5fcac7618343cf43e0a9c1e686baed44074ae7b97d04c0765cabccbe72e45c90d753a4f122a57c5a74fc9189e7b51426a3e7140f4e7c3dbda00969b7c7f9858cbc6d164e709d222b7d54ac24bd47ed33c5e3cdd3b17ea9ca5e7594d9660a4268d6aebd601b9320ea53d9ff0380294dd2adc84b88c7a5b968bfd44c076d0a79488f114809ee7591fff2bfff070674b0e96e410000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/stress/96kb-32 b/cmd/precise-code-intel-api-server/testdata/filters/stress/96kb-32 new file mode 100644 index 00000000000..2d4d0796c07 --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/stress/96kb-32 @@ -0,0 +1 @@ +1f8b08000000000000136d5cc98e65c952fc975e9f92623a31f001887f402ce00909846816efbd15e2df31371fc24f76ab54559979cf10e1a3b9b947feef6fbffffdbfffe95ffffa1ffff8f7dffff2b7fffc9fdffffadb3ff4f6fcf66f7fffcb7ffdfbdff0cd3fb7773ebdcf7acedccfdb573f6f2be569e5ac8aaf9efaaeb6e778dadca3cfb1cb237feaec5b7ed62beedafaa3b2fa1a75b781e7bdef18784f9bb30d7cb47ae1c3fa8bcbc65e65f096b78db6b7be6b9e07776001f3a97db4baf0daa79ef68c7a462f83af68f22ab9576e6945de80fb87fc1c7fcaf3abd5da4f3bad8e67ae5af6c10316d6b406b69956583bbe697c531f58a33c72e2aef1ec56440e138b3cb5e9b65fb91bcb1db6536ce79d10527d8afde13364a5b26bd9d816f97c84529e795a99a5ce07e2cc6bc1ea4d12b6f32e6fe3fa45f2781c16d2eb104de0bb24dd3de66edd64d42ad492968e47bc2fd46397c99b4a99b3b7238fefef7cdbc45ed34a78ef5bcaa630d6c2d2ca1ebb1f2ce8abffbed6bb60290ff6b9e529d8c0be66b34d6bdc47e967af0371e05aac8be22a7d95baa67cbdbfc228fc07b2c05b3bf5d15e5cf5cbae79a7e8719c0913b297257b81829a08aec9729efdbeedad9de6fa34aaf05edae66a14ae7c30ca112fd81487daa75af85b29ff3e218281474257f2d1daef30296189a24ed8196cf760d758bae88b1a3d6ebdb1d6557ba1d354d9503bb2dd46eb9bd89418f0584dfea9fc7a9e176fa6714e59a73d4d1d10fb6d6de131eaa4504db365e3d9631d380d77dcc73e221cd924e58b9f9e39cb11a39abb8a601aded2a91bf9d74c6cdab777ffb2b32d9bc582c451a84c5cb3e64e265bb8a53a1ba24969552e9aed54f12279006461cf70dfe2aa281a893d6f1f6242b4c6869dc83bf094e9a1e26dea60db0242f928168b586314330bd87373effa85ef20945db75b7dc70b18becc6b107cc61427d21ba0582ed48dbc84f8cc48c2fae576685514351840b0cd6a7211036bb5211425a7beeb8d97fbc712b3689667f256591623c6d82f16c815c1fc26978e056d0fb36aacfc1c9edfcd9ae0bf532cb7c3637b5d0c0c1de2cb17e1fb2d3fa154de22d25743fa3c217b690a6b4d5e5ec2bb61916f676411212c3c7c70711197542a5543fa0d66a65979de9ed87261dc2bb64a914d8774cc434510796df118c8994f6dba78d8dfa1e1f04dea44721f02c33b24538df019598daa9ace82acf19e16a90efb9b6f1163f2e4814f06d3ca5db9bcbfc2470b7f4e679d629073e251cd62db0d5b90b32c0de1048650cd0bee4e4679212f09425d8c07d2a0a342ed6e16ed938dafd18a0c1188862448cb74e66bfc5022980842acedf4a52e44b3117fb2b0b324825a806b4b02293d7f863e340a47dec44299fa1c2aa85f870b423853ec9ea19128a3b7fdb523de2e3228f630c6893573264c8fb688deea791132f982a3f84082a2c895fbba3169868804d59473c691752395d31ee7a07c45fe9b499afb743f3d0c695c6468c86d8481152b7bfbae557f3c6bf94007b1d93934f59dc5742119ad4de01571607c9c823b82882694709981e85c740f2644be9436db8077e8e054f475186cb6336831b04ebbbc63d7a1d870216e9d26405b902f87270c938f871f0b7977775835024bb3401cd2998ed3c4d6dd90f0b43e6efc901dadd6cfe182f5628faff2324f24fb7802370dae49ff2d17b7b99b36f591d9094fd44b34121f75306e80cbb5987a3a052af0521ead897b3e34400d7b086ffdac96f1dc260c8dc56331d0e412b59a486b9f1eff4d06665008482f6c9642f14027a935acbca52c61afebcd0010903a81df2bf1624b6ad5a767874c29eb4486342939ce4c984f329558e707f6de949441f57c52de16e56139005986e6555af63ebebf65c412612fb267988aa6b41a895a81f296a7207adbe6102c01055c88aa9379bd461ecaa426cba2dc93e7df6c086cf59610ac98488a2ef67075941df8c6de60f0611d8901a32c0127cf4a0fd0d7228c98016f31dd5309f7107a1f6270fc7d15047bba17a8f32269e2cd0d0017b2de6f0ac99e1d1278d802ca0c1226e57a865213ac1a8caca68a126f20359713d9b3d56a86c8cb2571d6fb2215c8358b1d0599a43fae6ca404c6a8013d2b1886cbca7fb5778fc6eed61ea1e427073fec1a035f77ef6aa1d6bd07d9cad2bf250af9c04167fe03b364829ea76cfab2d5b3ed83b7f67807a3d17d0b1c7914fa8dc6c06bb616d110b63e997ac10ca61a3b7e8074ab9a3a9db54f6ddfd4a691d4eff6f42db95d9da657b89388658c8871beb4fa593b452048407fb8358d03f54c81586dec48041210a719c7d432e783e0188624a70494b79402a115c8625f5147e16a5b5806780f622a912db479012a329a9653ef546c26758e54cc6aabf0e4613147aef624ef602aca4c5faca2fe234a9440e48947319d2e0fa90af74a10550395d727af940b3acbde8a1c3158a88a90e4c90ebf6b0d63f295317f66cc505403aa8d59524cf3b82536fa364794d867417555e29ee36631f651ec52a620c48c6469c6308dd5fe141e6b5c35bb914fa7d88ccae4700b210a4bd4083648859a701e87e9990b104499088ff1ae40e7f10c6ca7f295dc35821594367c156aa6621a5d4c5a0afe7556066ef2b2c3886e6ad63cc24cd48642052170245c9ca244c4662dd8153b2cda9e94c278445d4724952a067ed55342355b6362a0d624e46cb78cd94725bae0fef6be604acd0ec25705791830a4d4249661b9f03309e53f6ac34b471810236b21659c3ddec2057585504da9a03ea2e1ccde752f254052797e565c6f1127fc056f2df839f566a1e25601a132660c381ec122321d962e755f291e450cde05a0d930c6979838301e893923d85a8163cff7131e154b297841deebfd2b3e88ab6a42cd214ca33f4d27c179aecccbfc005178c72ae2377a39d7a348a324b6caa520b63dbbc516a982a7dc0597af90177300b2b75c9897436c8292879ae536688e029ac922c58b6a6499480e4316487d5404903a0d485a0c65fd2504942a8f80e25788d1204006a46de6a5f1b5921e431f43ed47b0e6c5e396cc58d522e2f78438558c0b027e5d438dfb057c81c6aba380a579801f89ce94f6eddb18c917995984ceda99cb276f32e845820f058d6dd1a03b1bc2a95190c2965a1e10daacf6359f4c06c8d694effc23d5d03a3fd85a92a8e74c257b85571a41df495e109b528b96125c12cc2a425cb232bc30d5286bc6f22e59eec82e332091fc3a4df3ac8561a1e2cf8eee54f717adc35edb26198370c04a63a542c5f1b059e51edb48e7ea4c48e6cec7c7e7753b2434f8656419125ce2f06e6e7d41728b5918e52071a6e3b3ba13806509718431c6ab95c95cc62224465ccdef06369a33f62664f24b44674434b6eaac863c68283e17033492820c8353be2c9219ca25fc11f1d86b6597700f2261c0d5ea5c0a8c145e28e94f16809263ddfaea6de5c3497389529524e37259be6ee86fd986eee727be4a5b020e8af081dc77b63977919afebcf69c358ce76652092c671470a00dbc460c60b12fa29b4635da242de5cc509e92ac4e423ed3d64d988965232c6a6d59e42573e2d529c15f1da4c550445817a2f3edd0259ca8b428104aec84602c6f50cb15f8fad9e386682bde9d81f40c8c1034c6ceb60228497a76495534bf91dd28d389d03ee88570c753c3cda195e38829f6ef3ad43b9f2845b42432fecd2d547043337b36d2320ad61f90ce1eeb81da204db04f6eb785d86dbe3961115f13b14298aff212b7faecb512b738744640923813f8ed0673f590124860ac960521ce5c95825fb4d69009691c212daf6c61f047dd050b5b8a24eceacbf6bf5e92a81f5a4178973acd666ab3d062ad25f72c79d21502456669a35f4a9b2f4b2c421d6d78d87ebcc437dfad8a6e4c365d31e14e7e924af20fed54bd09f867156949755fce25d699c2859df71ad930c205572aa1126395befeaca8dc02d836ecfe9c6dfe2db38ddc38c0d272deab8e50a173856188ed6db04c4472332b5473bfe8419b420bc1ef5df3067817522f1e8fb1afb79991c38ee0d722732b43ad43847877a06d862acae1a758535a70faa8467368a8169075ca051fe304aa16b8a280c617a7e5bc54a3a9ddaa84f19236e387b7d077bf0d350ac12c2b9a720044504a9a16ca078a09af8a020c5e5b4c1d2f53e6eb1b174b9c55c2e4ba6d2397872215e49aa1b5b2677fb7226b880ab7dcca4dd988868937750310794e820440a33a7784ea8508c81c0be15b2f392805185b218a72997b5f57d4a18d0291c7226fcec87b22e2054f3f6143c5da4b52d5c79aa687b4a6e1746bb3ef17e0f431b29fe5810403dcf8d6db5040e4166e939dcadbea1023d84ad94b9a312e8451a5499522cdd7284307531cab4ddf52e2623f7c8a17e6b2eca598eda3872d3bd0177b21c4c85fc4f8b2cbba155e425a428323a6b051691f48416a3d51587501029e89d7bb2da0ec7cfe804fb5ab085b79b87efb44084a6d92777ca542d94543dba2c199b3797f3fb0aa518c35b666658862c4d1853f3274063d450abddd25e3dad22e72fc0946c2888ddb770a7f50cbf6de7b0fb751d36709331314f244cf86f34e4ea23cb3d768a30c21089b7057c599f7b225a4a44633dbfc6aad45d352a2df12550ca366879cc81406e21dac4ca7c06bb492f882b5edd9cc3b97b7eb900befad4221be0da7dc55a9aa314e6a41c3e4b7f67bd434e7d4306d59c908fd8dbf9f428fcb7a1fc3e1108f38800515dd73cf64b917f87816928284370140ca240985281f01104edb93b168e7c9d1d20c80761bf1bc641cf28308ad4bbe3990af5e28cbfe01b4b6a3a862cc8e27a5866c5b7fca15e0137eabaca4f386249954da3a60519e3cb252193d9df7b53c66d69acaf51c169c12bfc0efd6c417bdb946612a0520a3aa502edcf4a19c1b995e57337be7873d2d2fa0b4a0b176448ec1ef87c4bf8d9bf2032656e153a13224e76340ad6966354b6e36483184ed520eae4ce6d0a26bbc96cc2d7e38fcce3aaaec9b5cea893a265c6ceefa2e330aefac39ff67cf1a316de080d11848198438e73bd7531c11ebd392cdb18037b5e84c4e92faa6966ef28aa905ec0195f98ee8e9022c4a5d42bf87fe9ae814c181221ac19fef752336a3f68d0e9211f6b2c446c55ba9e511fa97b24564a6f31ccb8c3200f5ed662b4296e59636bb7283daf76e99b46500170783439021614b611b6e786bfb32729e80458df5910a4f71a3006980475262c5809f968f6ae817d32cd2c19cc9f97603ade11a6d7b9b3189785fa57da41c53ee6e63db4d83427db0fa01835dede3ed3e066511f81673af34f214b83e1f80aceec49ec648936c5a9534c91d5a7596a84f792d6350aac3dca07f592451684718212360090ab0c958b68d11d6ddabd88b91b333b9f1fa2c54f772b9245afa06aa10a5ccf390c6066430d6f26ab0387d9e5020b3ffb2bc082c8a5070ac47710a1761d45831bd25c2d9c57091e872207d3b1a6de7c6a872006f77b4f7612b62aacb073e3e9324ef540e859a8d2cc209185c75383310939791cc52619f383e1d590a0a854f3ab701a3236310db784cb5dd6714c75462a1ca88ca0387001c681c0b857e21b315ebbae49e0a4129b3a1925626edc3463f73fc71c75a9bd9904bbfe1ec478b9f894c9b464093c0339a1fc55bf57d2d54f4b62fda40dc1dec7cdf292e1fad0c95fea14d2f636b505673b6e543afe23feda76e695a28c9347afde10631f0923b9f51a3a5379af43e6fc9b348cec51a4b721fe79777874b3fe64ef9a45fd2a4169a74687f5c2c200d26249891ee899949ef966beb6cb06b48688035cde09886cfbfc50663d028d1c08930ea5263db2404cadc463e84119d3189204666cdca82219220d296ffd7db72275f4aa33b661875bcd0807b7ea14d9ea7b131a1991a9fe5f9b20a6bed962a96cb530697278f08a7bfb34cd2357cd5fdb1117e64a1c84bccfd16ad6158c5ac5255f6801e87eff402ffe6855bc429f75f93977b460c77bab7fdd893c6934ec792af3f0ea91f1a6707dbf25ae8b6cb8a4d4f6984d7c1b22f3d992b068e6a7a6b5592a3f8cf3e3311789c789529b1b547f2ca6c928afeee4c53c6477309499d98a4f2d3957ca6593924772e40fd66e1c32bc24fdbb2c590cdfee3e0060d9dad306f362a52435647c23bb3e470ec7358ae22770f63cd25ded7fd1921c83b6f3fc3a1c49b777d58bbf2e4c956ea9b2c8d9ba5d262db26221c593b453f13d182583b17ab8bd488958470074dc3bb524ed489020fdf9f002cd4a031513e84faf15d99465b8f737ef5f15a591da4e8fc3fa39cce3aca8263e223cf0a78ba3bbd79622407a983aadeffb9fc8d6092567e344d65aeb7cfaea31353272dadc42e4c44a84865aa94fc260bb75bf5b46eb3e50e5f7f097606f0ebc445ed0cd5956fde76fca3c26646ed1fcac5ba840efc0b0968ed4ba681ce3be1a2c48b55dad1f9b0c68081f0a22c3272fa100bd825eb240f81d198ef477d18896e6702c838f5271765517bb0906a5056b5fe96d6b3d6a6d3811a0233c6b14e02e3965a4e667d82098c025a11b58feffcaa05983bbf786dd0c9567517660214b4dca0c6ebedd46011b33f6d554f6edb8662a1b951c6934b7e1fbb96f0531019bf538680bada4f3d9ff69c970c829b15395b53a9ce1845f1579821e7bac927b5741c80993760a21f92f932f877c80917add1ee58118349b9e890235ba26c65182d1ebd00edc7f1e6c5da39f42449db8438493583098ab56bd512d0b00591bb844e24156ece96c8ee539480713a46b14259b006fab0644166d2a684d53e3e3329a28236a7e736469492cb596d86c9dc6179b35d23a265f6380d34b4f7e47e85a9c512449e5df0af1cf6f8bc59d3601f948064fc3b041553599663d578bb4f5b68b761c764623a3e8530d1242206631e539462682f29edee1d1a6b2b3943e01d1583a5da0c5566cd667523c1e6d1b63b7edce2bcce9fb95c6682f4d852705061de92f27932e24baef02e859971464866e088bdc9bdc865e43acbabcd5bb64584dfd93b81ec207c6ffbc233d8667ff81e6039deace4e068109953868d9e0a08f86eed95fd1c4af2099aaa83c46c3b4d264bcf84cec519012cbe65e0aa658c60162ae719603dc045aceea5287c152e7a385606944856c2ca1ed6bd51e82240e8a26edacb79cfba13e347fb5b41a05b70a049589b8443705188a380688d83fd4dc2ce30941a27a9e464488c812802e139aa2f0ab82710f3911d998d819dcab9b99266f28c958bec49765b7a14d681d2937d1c8af4b9ea74ec87a32accd69f52f2c3afb89bdf1386dae55b727c201fcd79d30cdccf19851b7aadafa613ec9cd038ace8bcc66907aff163090147bcc4c9e388661166f2de5e3c2236c77e22bc99d2c6d4233739d4dbf8cacafd7f213d75c0bf5e801ba32f487930f1ba9da2251db2094d59febf2980e54196842113151bf3e2cda684a2a317934c9704d58dcbc8f2678064accaea4086628af37c81efa305abdc80ce6f6fe9661e6dd0877f5a1f3458e50bc7ef1c3b4a2f6094f3637274a70e9fced30854f1c9a0c05c83239e33603cc21dfeab366357ee78439a3dd7e313be776d235fefe349c16f069ada063ac548133d5b7cde661fa15cff16fe7192c267395922afd4d5b158a8af3d4c14e2f5b71a89c1c398d4da3ca4f9ded94b6263ead8c7df1dc0ecfaa53ebcb09c31befdc71aed4e53ea081d1f2132176325217b4c3e960da3e9a8c1cf5931258d750647e7bfc92c644448e0bc6f70239b04b0d6943cd4da3a6e98fe0625729b31c90ae97d7040f0d9826bb289f6369903bac332bb3b7318075038392f9ad49a288639266500d92051ec775f97bfcc9b22679f4cbb961287613fb37f4ee1bcb74dc9e1059b6b4ed5ae42c73846ee8934e6ddd23c01eda67bc0dbf990498dca3621925c0e2b79f8b377baed2ca637ff889839cab2626e2392ebedf5c51c6b2a0903704ba75f5b1c464c022aee8c81bd8c1128bd9b9511442569c8f0fd9ea1974c4f12da2796ddd7ef5c7f09f497e61a4d9a2551c2346269ec6b6f4307947ce012216fe7d8e9ba43b5a543e1bbf8c4b7d6913197ceb1df38eb22be2eb30c80e671e806f65c3dacc80c2fe7b456fa2ef5b778d12eacba6e458ac51d540bc7264af5dc057f2f41c9831337de786e54a2f089d9a99dc62d2b36df8b765f948556a67cfa113edcf34a23e59eaa789f92a5d3322f313e6db0c16065e95d9ac6e39ed63fef8f4a4609ef4bdb2b4848db7101052f99cffe7dfd8fbd791fe71836d81c4cf36714ca28551e22bfc31cdab25dcf777403e17295916af55beaa69e82bba71f36e35385fdb1993b2766dfd5e3e4dac9b508329f9cb6e23024cf2af41f27a1afdb28a940b29fe397b06b9f2bd7c3ea97474fad26a3e70cce40538a0ce4486d844c1bd73288e367c1a2ab1d4331926b7f8efadb920b3b7baf77d4df4fef2439bc01931f7de51b1e39f9673c7f4658716253ac89d883a7b779505d51efc197f306823f301404d36ae573f8c90e27c2de0fad795bc2d74f6224779728914eab1fb1b37776b99244eba62313f9c8653acf10480265177fb5c36015d776e4c5c101a85890b5319537eb93334062a7111c6f771e20bb56e3ec184eedcc86c419a01e99f048ec83ce5ab091315be97359bdc353fc9d787cb77b720f3960def17f0918417a688e323a3bcd47db0a8d33945feb40465ee3d4b73e08e49e062b9022ead07324da8eafb76828dfd2a8086860c4b3633849c9d1389eecf6af1821ace59ec06ff60b3464e78624e5d8140fc4640c99c0b66452638bece847d5a4b1528769cc54d9bbab1143346b9ac4acd4e55deca4536eca265712079ccddd2d9da5d7975c26cc86202e57694be4a49df5f4bf937a3c3517fcb3f2b4d57f4fc47eee10561bab7c467e6f5ee672c60505357b979e2dcdc3b43e6ac54347a7fce03c3e4a8e3424edc222cea0470a7ef0fc76984d6620798e942a29063332e596bbe32161d9e78ecbf590779e2872d954a9f99ede3e0bac07e0611373dbef092976381f1f4b0576ebc6b869aa268179a605fc0b51ef21c01f47eec498ac7fabb8d0ddc63b2ea9df69bd52ff1d4af1a41ce9745546487d27d514962786a9cad992b27c80357e0345fc4e1987cb23a0ada500824c692eeff8653f0498c48c94b7626fb64cc7f093719f0e30e7dbfaf1c32e5a33bff57b2479a702e6e6b7f85538fff27fff0f3d7c6d9b824a0000 diff --git a/cmd/precise-code-intel-api-server/testdata/filters/stress/emojis b/cmd/precise-code-intel-api-server/testdata/filters/stress/emojis new file mode 100644 index 00000000000..bca6caed470 --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/filters/stress/emojis @@ -0,0 +1 @@ +1f8b08000000000000136d5acb8e253911fd975e6749e1b7cd0720fe01b180111208d12c666685f877e21de1bca552ab6fdd74daf13c71225cfffdf1f3f77fffe9afbffee38fbffffce5b77ffee7e7af3ffe50e6f3e36fbffff2afbfff86bffc79b4b9179c529fb90aec3dfb53ea7eca6c1b3f3d75ee01704e7de0a963e2efbdf02fe5cc09fbe1d74b99fb9973e3cef8b437e8b8807e3a9cf994d24f6da7e2c70a679735e9f5a7b45ecb5a7416ac5e1754a063f17458678dd3f0639badf4bd69ab39f0a8a7d3e286cb5b9b7c02be40627dd5d2575fa3d3e7d1fac2454356b4b1cac24d9f56178a890a3cbba19e78da5655e642395a7f0ebdb1fd307e8cfaa94968337da3fa1772f06eb3d3efa63deab9caa86a055c0ff878d45ef756339f1df6663d70c560cb889885a5409334da6594ca92a1377a1b7d76d991edd2c59a503bc4962aa7fcb4865bad43ee14558b588676c5edbbaafb5566813660888a72d458cfae4bac9484b4a733b9511563efae06a83f29935e02d5941c587625c1cd131a2eefc775a279fbdbca786e1d87b6e7035ac3c0a3135c7b0e3bd37d8cde5bcd4791ef5a5b851543b576c5c324fe0f054a528eb300ccb368afd250c08aae9000b04d399c5b9980f2a89f2d1648a18df66191cc736194fd6118f6f88c20f254699650c9a2153364726cb50a976328ea86079fd9320569792d2f98a313ad08ed6002f2fe142111cb034f6f2eed589d50e3abec75a0eb92db511c9f39ca41adcfbf62caa31754885176074f6f76bfed50167a0b616828ac58d68a510ef964900d20940cdbd73bbdc4a11a14fd9582ea6c5655503107557276721e66ebd6f8f55d6b42417658981097af7a05e62b05f0e8051dbd4a88ca69e9d1c7fb6505d4c695bdc7dbf4487ad7a172640df43305aea686c6a82f127ca12d085053505c5b95bc7d846d446313e4a875d5787a606f35b0820f7bd0de8bbd63770ca74d3044b11221e5625372d0aa8a09db35a346c9f9051901d17a784892d820ab27353c3d1806362570a088fa518e074da9d9c389c07525950daea1081869b1417b365edac03f36939b822596520c2cca2bf5bac683e01189970cdc43cf5d1a45314bc6479c6e29413512a05856d4e4208d49320a674d2f618a0db38d79d4bceac61c23093f2fecf7a0bb4b007f7160148411fa957c68ce208c420a30161be5eb7a1152d666dcb143430cde6ebaf99b073b338e1c949fa18ea037577e013c2f95749c81a93d5aeddbed7102363d8a5cc462cc2595e2e4ca8569dc23ed36c23e996e12e3d177ce151446b7a212ab0eddacb4290c23dc7afae5b0c1eafcd0dc9de547dd127359c37fd320e885a5ac4edac05ffe8e4478c9463597729dbb9414f472c1d7355939b6f68bc151a1e0f2bb91f17c98586b01624679898b6f8c9eb1005ef154a3a2480c35b4a1be2a4c8073dc391909889464d7a1868614b09b4383b3b4714df0da14c1cdac5b05d6b0e00f85e34e1f8c869c62931ce1b99c709fa08d87e2ce22e3f0efebfcd078125b51a53dec98cb6572e63ab32d133520a36c82327c50b8025931f0d7f1855ad0a00a76428a72ced2a90566a1bc62e1465b508a14512ffe9956768440c9a44b170775a186e647435b879a4bbce90a7a26644ca414f2c40e60e0af2442c2f81a31761ed9f2d499841274a1407e1767031ac692697e892845cad44f22faa87745514edd9673a138ee842d155509a597b9ae428e5d415d475ba082e7db908316775f6f3c0b30ba90e04bdc5897521967b533306e1571bff22f0ae960de1ced0a51e1358bddc771cf2269c9d32e440a7bc19ecfa5703f00b0409d3c48a3233929003e253590dda298bba78a1295c56326f08884512b7afbab960c359e1ba8a589b8f9d640b9d72bd592e61263f4db489446f8cb04f38fb45e58a64741e697ca8437694268da6ad448a94c67255e262bb7d1086a2f83c7566d8e5daa8a584684e86232f060477eb0442af575f2534f0f54c0e5d81f81c456ef940f1d19240487647bed71a71b0279ab9e0e9f505f2ed0b56a1fddaae696c3ab7c519df50aa136d3f67e29908a1bd96bc11b768c3196d89abf8835f3710ce191c738d64820dd8a421280e8dd404e22ca92fd64d788f5652c6094f529129f2933b1413f1b79eed1f04d4ed333d0e255470ea8d145eb3c05f03ff2979d2e388d07a8ea0b21be9595bcb2d1fe4d7ba76c2fdbe13b0a76359158bc778de0b96dfe1aa64c4ca102eaf64105c223eb955e62dca89e049895ebb3a4ac70109989cd0b71d885ea4789b263418b621d67cfcec0d162c227266fff266dacb594565c47d40fbd545fd137e01c25f21f3313392876233e295d45c19f4809e9edfb76575e96d7b8b15305a8aefa9d6710bc41794b22f67a63b9b120f756b4ffd45b3c5adf392be5f840af908fe107c3a2f2584097935094b21acb1f9c94c450ae326fc480279529dedbda01e2862955036e0ff64ed2166512ae16dd743cb705267017eee0d94c1df9e36d5cc2148988b313f7738cbae3dd66b231ba18798c9b67a2193cd8b5e7c20cd9457deef4434b371065b40d6400c5a5cbb4f56c837636bbde77506e7828e32580782bd7638dc6565699870d3a0de2e9138fe4e08d4fa97760898e656a4e2375cc5d61d9b12aa158a045c018218cc99c3f7276d3d94575080845ff78877fb4f3f6217cc003ef398b239c93427364c042845c01815ee7768929fa0c3447c2e7384e8bfe4d4d930ec81f0fa995e64b3c24fed025925e457c777f5703e9f14be61d315e983a726fd76580014b16bed56cdde08a932735dfcd1d53f9cfa424bee329bb7621c7e0808ef24e512f2b745ae5c3597e4c33e85990aa11bcefab03a58d93399c2c66190772d0ed9cb95ecd7b89f9e1fb7f24736725dad71597c9bc672a161835a16ea062f5d586d26621ec9ad1aa87518c3591ecc396c636e4c9b993d44a23c9bb293cdf8c823dac2d14be2a1e846fcd51afc3622ee9b322dc842e34aa4d72991cc580286a0bf2fa4d2595c68253bb222d7ef86f08ebf096eae6dcd81901a6053c7697e2268eba4bb6c68abe9bf5648788b3bb2665ace5c6b7371f6d5b56e01209c21a85d00656c876d13627a050ed3a2764f57dca39b38fd33cc0a4f212ae24f1b162f5a65b21b4d19ddb0a62ae05441fefb9f90b081299f2af928d58eb7822c825b69a3719d2dbac14a9115c4dc73fcd67b95c92ec31d558da9d3b391f15edd1d9a2ea7cba87e8fc0063a0369f3070a02653ced933e75c766d02340304a26af40079c1a1a118859c785a9d15458dceda183efb6d916f2ec6aeae4963c08655e47316c1aea8a603df80d68a4dce9600b2360b147f33a76a69ad389f866c22f83ef9ed1234e9c4cb680e6af75fe7b976bc68a1df94e97819bc4dce6e4540a369c58dfcda61dafacf9b0aed17ea29f4edb6ecbefa09ac82ebbb7bc6a7d6ca385390052ee81158399ec088f97d7ba997a979546e6f77e1658a3c463d34783049284c10b2687ef568eba0fdee37644675b7687ed2049b52f0bb097990e3b1f647a7d8d200754afae0415c0addd5f9122ce15b0adee14d5e0c3117729c3af86678628c8deb204615c09fdde7f417a92cd0696844bb1aebb76b19d5131631a5f1eb45d97ec30b7b3d531c385f239cb839f98073b9b8790440b343d2958875d9c673740e74392326804e9a9847966d3042d7c4c7c8ee02fa730a4b7f0b9a0503cb4f0b6f7a7f6ffe13353be98e51db0e609fc2a39bc7eb85377c18ac106569d538c8ebca7744d47b759d84dea3a03a74c698fc931b47fef38ee9b17e77619bb949b97bd1c87294b1e3c9d27857043a199f6c316bbaa1f00f136685fca719afacf0dbbea21e9669d7221ef1188dce899265363f3ae72b2f79f151279a0fea54ecfd638a7ef2ddbefd7d09beefd3b9fa08b5d7bb6f19af991e2358c685ad120232edb5eb7b4a8871dd0ea4593ed18dd6f7b65b8544dbbd19510d64ae2602cf37b2aa41df901cfa6daa18f39a3485c97c7dee92445a73349bbdf5e8e122401cd2bc2f90794e2b2577c4798c04d871b55932e78cbf7c98d7c50b330884a4cca7d259d64ac8bd9fc4bbbd9af24841b8bee6e3900c1a81a5b64cc996aecdd2649bcffecbfffe0f45902f1ae7250000 diff --git a/cmd/precise-code-intel-api-server/testdata/words/corporate-ipsum b/cmd/precise-code-intel-api-server/testdata/words/corporate-ipsum new file mode 100644 index 00000000000..61e6561a857 --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/words/corporate-ipsum @@ -0,0 +1,59 @@ +agile +approaches +bring +capitalize +cloud +collaborative +content +corporate +disruptive +diversity +domination +empowerment +ensure +evolved +forward +foster +frameworks +fruit +further +generated +generation +going +grow +hanging +heading +holistic +innovation +iterative +level +leverage +multiple +normal +offshoring +organically +overall +overviews +proactive +proposition +provide +real-time +robust +runway +solution +strategies +strategy +streamlined +survival +synopsis +table +thinking +touchpoints +user +value +via +view +will +win-win +workplace +world diff --git a/cmd/precise-code-intel-api-server/testdata/words/emojis b/cmd/precise-code-intel-api-server/testdata/words/emojis new file mode 100644 index 00000000000..5f401515d56 --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/words/emojis @@ -0,0 +1,106 @@ +โ˜น๏ธ +๐Ÿ‘น +๐Ÿ‘บ +๐Ÿ‘ป +๐Ÿ‘ฝ +๐Ÿ‘ฟ +๐Ÿ’€ +๐Ÿ’ฉ +๐Ÿค +๐Ÿค‘ +๐Ÿค’ +๐Ÿค“ +๐Ÿค” +๐Ÿค• +๐Ÿค— +๐Ÿค  +๐Ÿคก +๐Ÿคข +๐Ÿคฃ +๐Ÿคค +๐Ÿคฅ +๐Ÿคง +๐Ÿคจ +๐Ÿคฉ +๐Ÿคช +๐Ÿคซ +๐Ÿคฌ +๐Ÿคญ +๐Ÿคฎ +๐Ÿคฏ +๐Ÿฅฐ +๐Ÿฅณ +๐Ÿฅด +๐Ÿฅต +๐Ÿฅถ +๐Ÿฅบ +๐Ÿง +๐Ÿ˜€ +๐Ÿ˜ +๐Ÿ˜‚ +๐Ÿ˜ƒ +๐Ÿ˜„ +๐Ÿ˜… +๐Ÿ˜† +๐Ÿ˜‡ +๐Ÿ˜ˆ +๐Ÿ˜‰ +๐Ÿ˜Š +๐Ÿ˜‹ +๐Ÿ˜Œ +๐Ÿ˜ +๐Ÿ˜Ž +๐Ÿ˜ +๐Ÿ˜ +๐Ÿ˜‘ +๐Ÿ˜’ +๐Ÿ˜“ +๐Ÿ˜” +๐Ÿ˜• +๐Ÿ˜– +๐Ÿ˜— +๐Ÿ˜˜ +๐Ÿ˜™ +๐Ÿ˜š +๐Ÿ˜› +๐Ÿ˜œ +๐Ÿ˜ +๐Ÿ˜ž +๐Ÿ˜Ÿ +๐Ÿ˜  +๐Ÿ˜ก +๐Ÿ˜ข +๐Ÿ˜ฃ +๐Ÿ˜ค +๐Ÿ˜ฅ +๐Ÿ˜ฆ +๐Ÿ˜ง +๐Ÿ˜จ +๐Ÿ˜ฉ +๐Ÿ˜ช +๐Ÿ˜ซ +๐Ÿ˜ฌ +๐Ÿ˜ญ +๐Ÿ˜ฎ +๐Ÿ˜ฏ +๐Ÿ˜ฐ +๐Ÿ˜ฑ +๐Ÿ˜ฒ +๐Ÿ˜ณ +๐Ÿ˜ด +๐Ÿ˜ต +๐Ÿ˜ถ +๐Ÿ˜ท +๐Ÿ˜ธ +๐Ÿ˜น +๐Ÿ˜บ +๐Ÿ˜ป +๐Ÿ˜ผ +๐Ÿ˜ฝ +๐Ÿ˜พ +๐Ÿ˜ฟ +๐Ÿ™€ +๐Ÿ™ +๐Ÿ™‚ +๐Ÿ™ƒ +๐Ÿ™„ diff --git a/cmd/precise-code-intel-api-server/testdata/words/lorem-ipsum b/cmd/precise-code-intel-api-server/testdata/words/lorem-ipsum new file mode 100644 index 00000000000..7b0f709ce5f --- /dev/null +++ b/cmd/precise-code-intel-api-server/testdata/words/lorem-ipsum @@ -0,0 +1,145 @@ +a +ac +ad +adipiscing +aenean +aliquam +aliquet +amet +ante +aptent +arcu +at +augue +bibendum +blandit +class +commodo +condimentum +consectetur +consequat +conubia +convallis +cras +curabitur +diam +dictum +dictumst +dolor +donec +dui +ed +efficitur +egestas +eget +elit +enim +erat +eros +est +et +eu +euismod +ex +facilisis +faucibus +felis +fermentum +feugiat +gravida +habitasse +hac +hendrerit +himenaeos +iaculis +id +imperdiet +in +inceptos +integer +ipsum +justo +lacus +laoreet +lectus +leo +libero +ligula +litora +lobortis +lorem +luctus +maecenas +magna +massa +mattis +mauris +maximus +metus +mi +molestie +mollis +morbi +nam +nec +neque +nibh +nisi +nisl +non +nostra +nulla +nullam +nunc +odio +orci +pellentesque +per +pharetra +placerat +platea +porta +porttitor +posuere +praesent +pretium +proin +pulvinar +purus +quam +quis +rhoncus +risus +sagittis +sapien +scelerisque +sed +sem +semper +sit +sociosqu +sodales +sollicitudin +suscipit +suspendisse +taciti +tellus +tempor +tincidunt +torquent +tristique +turpis +ullamcorper +ultrices +ultricies +urna +ut +varius +vel +velit +vestibulum +vitae +vivamus +viverra +volutpat +vulputate diff --git a/dev/check/go-dbconn-import.sh b/dev/check/go-dbconn-import.sh index 98d9d15f15f..4439bd5c16b 100755 --- a/dev/check/go-dbconn-import.sh +++ b/dev/check/go-dbconn-import.sh @@ -7,7 +7,7 @@ echo "--- go dbconn import" set -euf -o pipefail -allowed='^github.com/sourcegraph/sourcegraph/cmd/frontend|github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend|github.com/sourcegraph/sourcegraph/enterprise/cmd/repo-updater' +allowed='^github.com/sourcegraph/sourcegraph/cmd/frontend|github.com/sourcegraph/sourcegraph/enterprise/cmd/frontend|github.com/sourcegraph/sourcegraph/enterprise/cmd/repo-updater|github.com/sourcegraph/sourcegraph/cmd/precise-code-intel-api-server' # shellcheck disable=SC2016 template='{{with $pkg := .}}{{ range $pkg.Deps }}{{ printf "%s imports %s\n" $pkg.ImportPath .}}{{end}}{{end}}' diff --git a/dev/tools.go b/dev/tools.go index b76453dd786..b33c2730134 100644 --- a/dev/tools.go +++ b/dev/tools.go @@ -11,6 +11,9 @@ import ( // go-bindata is used in lots of our gen.go files _ "github.com/kevinburke/go-bindata/go-bindata" + // go-mockgen is used to codegen mockable interfaces, used in precise code intel tests + _ "github.com/efritz/go-mockgen" + // vfsgendev is used for packing static assets into .go files. _ "github.com/shurcooL/vfsgen/cmd/vfsgendev" diff --git a/go.mod b/go.mod index 0677d7ec0b5..eff4e9b7fc7 100644 --- a/go.mod +++ b/go.mod @@ -23,6 +23,7 @@ require ( github.com/dgraph-io/ristretto v0.0.2 github.com/dnaeon/go-vcr v1.0.1 github.com/docker/docker v1.4.2-0.20200213202729-31a86c4ab209 + github.com/efritz/go-mockgen v0.0.0-20200420163638-0338f3dfc81c github.com/emersion/go-imap v1.0.4 github.com/ericchiang/k8s v1.2.0 github.com/fatih/astrewrite v0.0.0-20191207154002-9094e544fcef @@ -143,7 +144,7 @@ require ( golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a golang.org/x/sys v0.0.0-20200331124033-c3d80250170d golang.org/x/time v0.0.0-20191024005414-555d28b269f0 - golang.org/x/tools v0.0.0-20200403190813-44a64ad78b9b + golang.org/x/tools v0.0.0-20200420001825-978e26b7c37c google.golang.org/api v0.21.0 // indirect google.golang.org/genproto v0.0.0-20200403120447-c50568487044 // indirect gopkg.in/jpoehls/gophermail.v0 v0.0.0-20160410235621-62941eab772c diff --git a/go.sum b/go.sum index de72558e518..410c94db0ba 100644 --- a/go.sum +++ b/go.sum @@ -76,13 +76,24 @@ github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrU github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= +github.com/alecthomas/kingpin v2.2.6+incompatible h1:5svnBTFgJjZvGKyYBtMB0+m5wvrbUHiqye8wRJMlnYI= +github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4 h1:Hs82Z41s6SdL1CELW+XaDYmOH4hkBN4/N9og/AsOv7E= github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E= +github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/andygrunwald/go-gerrit v0.0.0-20191101112536-3f5e365ccf57/go.mod h1:0iuRQp6WJ44ts+iihy5E/WlPqfg5RNeQxOmzRkxCdtk= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/aphistic/sweet v0.0.0-20180618201346-68e18ab55a67/go.mod h1:iggGz3Cujwru5rGKuOi4u1rfI+38suzhVVJj8Ey7Q3M= +github.com/aphistic/sweet v0.2.0 h1:I4z+fAUqvKfvZV/CHi5dV0QuwbmIvYYFDjG0Ss5QpAs= +github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys= +github.com/aphistic/sweet-junit v0.0.0-20190314030539-8d7e248096c2 h1:qDCG/a4+mCcRqj+QHTc1RNncar6rpg0oGz9ynH4IRME= +github.com/aphistic/sweet-junit v0.0.0-20190314030539-8d7e248096c2/go.mod h1:+eL69RqmiKF2Jm3poefxF/ZyVNGXFdSsPq3ScBFtX9s= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/avelino/slugify v0.0.0-20180501145920-855f152bd774 h1:HrMVYtly2IVqg9EBooHsakQ256ueojP7QuG32K71X/U= @@ -147,6 +158,8 @@ github.com/crewjam/httperr v0.0.0-20190612203328-a946449404da/go.mod h1:+rmNIXRv github.com/crewjam/saml v0.4.0 h1:gvSlboe4BO1APaU2eDdsbql3itRat310Q5qs2Seim2k= github.com/crewjam/saml v0.4.0/go.mod h1:geQUbAAwmTKNJFDzoXaTssZHY26O89PHIm3K3YWjWnI= github.com/cznic/mathutil v0.0.0-20180504122225-ca4c9f2c1369/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM= +github.com/dave/jennifer v1.4.0 h1:tNJFJmLDVTLu+v05mVZ88RINa3vQqnyyWkTKWYz0CwE= +github.com/dave/jennifer v1.4.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -176,10 +189,16 @@ github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= +github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= +github.com/efritz/go-genlib v0.0.0-20200420163202-9c3914df9594 h1:wAEx9E0qHx43LRLQqP5VFTijgLnvvNM53FqLu7G+VQI= +github.com/efritz/go-genlib v0.0.0-20200420163202-9c3914df9594/go.mod h1:aMnaM7yzn10TOdj5sGpElY90l/XT3eL+Sj7z7D1V8q8= +github.com/efritz/go-mockgen v0.0.0-20200420163638-0338f3dfc81c h1:MPakRO9Z5EFrMOnZm1we5ngCCxlJuMEiGCRbesXLVls= +github.com/efritz/go-mockgen v0.0.0-20200420163638-0338f3dfc81c/go.mod h1:K2AZyo7TmaAzRhr4EvUaEHcpumiT0UEAARFnSBid7yE= github.com/emersion/go-imap v1.0.4 h1:uiCAIHM6Z5Jwkma1zdNDWWXxSCqb+/xHBkHflD7XBro= github.com/emersion/go-imap v1.0.4/go.mod h1:yKASt+C3ZiDAiCSssxg9caIckWF/JG7ZQTO7GAmvicU= github.com/emersion/go-message v0.11.1/go.mod h1:C4jnca5HOTo4bGN9YdqNQM9sITuT3Y0K6bSUw9RklvY= @@ -647,11 +666,14 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0j github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2 h1:YocNLcTBdEdvY3iDK6jfWXvEaM5OCKkjxPKoJRdB3Gg= github.com/mcuadros/go-version v0.0.0-20190830083331-035f6764e8d2/go.mod h1:76rfSfYPWj01Z85hUf/ituArm797mNKcvINh1OlsZKo= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s= github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk= +github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/mapstructure v0.0.0-20170523030023-d0303fe80992/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= @@ -685,11 +707,13 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw= github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.8.1 h1:C5Dqfs/LeauYDX0jJXIe2SWmwCbGzx9yF8C8xy3Lh34= github.com/onsi/gomega v1.8.1/go.mod h1:Ho0h+IUsWyvy1OpqCwxlQ/21gkhVunqlU8fDGcoTdcA= @@ -1005,8 +1029,10 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= +golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -1212,6 +1238,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191224055732-dd894d0a8a40/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200102140908-9497f49d5709/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -1230,8 +1257,8 @@ golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjs golang.org/x/tools v0.0.0-20200311090712-aafaee8bce8c/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200403190813-44a64ad78b9b h1:AFZdJUT7jJYXQEC29hYH/WZkoV7+KhwxQGmdZ19yYoY= -golang.org/x/tools v0.0.0-20200403190813-44a64ad78b9b/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200420001825-978e26b7c37c h1:JzwTM5XxGxiCwZEIZQPG46csyhWQxQlu2uSi3bEza34= +golang.org/x/tools v0.0.0-20200420001825-978e26b7c37c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc=