TUN-813: Clean up cloudflared dependencies

This commit is contained in:
Areg Harutyunyan
2018-07-24 18:04:33 -05:00
parent d06fc520c7
commit 0468866626
3310 changed files with 993 additions and 1223303 deletions

View File

@@ -1,319 +0,0 @@
package raven
import (
"encoding/json"
"reflect"
"testing"
"time"
)
type testInterface struct{}
func (t *testInterface) Class() string { return "sentry.interfaces.Test" }
func (t *testInterface) Culprit() string { return "codez" }
func TestShouldExcludeErr(t *testing.T) {
regexpStrs := []string{"ERR_TIMEOUT", "should.exclude", "(?i)^big$"}
client := &Client{
Transport: newTransport(),
Tags: nil,
context: &context{},
queue: make(chan *outgoingPacket, MaxQueueBuffer),
}
if err := client.SetIgnoreErrors(regexpStrs); err != nil {
t.Fatalf("invalid regexps %v: %v", regexpStrs, err)
}
testCases := []string{
"there was a ERR_TIMEOUT in handlers.go",
"do not log should.exclude at all",
"BIG",
}
for _, tc := range testCases {
if !client.shouldExcludeErr(tc) {
t.Fatalf("failed to exclude err %q with regexps %v", tc, regexpStrs)
}
}
}
func TestPacketJSON(t *testing.T) {
packet := &Packet{
Project: "1",
EventID: "2",
Platform: "linux",
Culprit: "caused_by",
ServerName: "host1",
Release: "721e41770371db95eee98ca2707686226b993eda",
Environment: "production",
Message: "test",
Timestamp: Timestamp(time.Date(2000, 01, 01, 0, 0, 0, 0, time.UTC)),
Level: ERROR,
Logger: "com.getsentry.raven-go.logger-test-packet-json",
Tags: []Tag{Tag{"foo", "bar"}},
Modules: map[string]string{"foo": "bar"},
Fingerprint: []string{"{{ default }}", "a-custom-fingerprint"},
Interfaces: []Interface{&Message{Message: "foo"}},
}
packet.AddTags(map[string]string{"foo": "foo"})
packet.AddTags(map[string]string{"baz": "buzz"})
expected := `{"message":"test","event_id":"2","project":"1","timestamp":"2000-01-01T00:00:00.00","level":"error","logger":"com.getsentry.raven-go.logger-test-packet-json","platform":"linux","culprit":"caused_by","server_name":"host1","release":"721e41770371db95eee98ca2707686226b993eda","environment":"production","tags":[["foo","bar"],["foo","foo"],["baz","buzz"]],"modules":{"foo":"bar"},"fingerprint":["{{ default }}","a-custom-fingerprint"],"logentry":{"message":"foo"}}`
j, err := packet.JSON()
if err != nil {
t.Fatalf("JSON marshalling should not fail: %v", err)
}
actual := string(j)
if actual != expected {
t.Errorf("incorrect json; got %s, want %s", actual, expected)
}
}
func TestPacketJSONNilInterface(t *testing.T) {
packet := &Packet{
Project: "1",
EventID: "2",
Platform: "linux",
Culprit: "caused_by",
ServerName: "host1",
Release: "721e41770371db95eee98ca2707686226b993eda",
Environment: "production",
Message: "test",
Timestamp: Timestamp(time.Date(2000, 01, 01, 0, 0, 0, 0, time.UTC)),
Level: ERROR,
Logger: "com.getsentry.raven-go.logger-test-packet-json",
Tags: []Tag{Tag{"foo", "bar"}},
Modules: map[string]string{"foo": "bar"},
Fingerprint: []string{"{{ default }}", "a-custom-fingerprint"},
Interfaces: []Interface{&Message{Message: "foo"}, nil},
}
expected := `{"message":"test","event_id":"2","project":"1","timestamp":"2000-01-01T00:00:00.00","level":"error","logger":"com.getsentry.raven-go.logger-test-packet-json","platform":"linux","culprit":"caused_by","server_name":"host1","release":"721e41770371db95eee98ca2707686226b993eda","environment":"production","tags":[["foo","bar"]],"modules":{"foo":"bar"},"fingerprint":["{{ default }}","a-custom-fingerprint"],"logentry":{"message":"foo"}}`
j, err := packet.JSON()
if err != nil {
t.Fatalf("JSON marshalling should not fail: %v", err)
}
actual := string(j)
if actual != expected {
t.Errorf("incorrect json; got %s, want %s", actual, expected)
}
}
func TestPacketInit(t *testing.T) {
packet := &Packet{Message: "a", Interfaces: []Interface{&testInterface{}}}
packet.Init("foo")
if packet.Project != "foo" {
t.Error("incorrect Project:", packet.Project)
}
if packet.Culprit != "codez" {
t.Error("incorrect Culprit:", packet.Culprit)
}
if packet.ServerName == "" {
t.Errorf("ServerName should not be empty")
}
if packet.Level != ERROR {
t.Errorf("incorrect Level: got %s, want %s", packet.Level, ERROR)
}
if packet.Logger != "root" {
t.Errorf("incorrect Logger: got %s, want %s", packet.Logger, "root")
}
if time.Time(packet.Timestamp).IsZero() {
t.Error("Timestamp is zero")
}
if len(packet.EventID) != 32 {
t.Error("incorrect EventID:", packet.EventID)
}
}
func TestSetDSN(t *testing.T) {
client := &Client{}
client.SetDSN("https://u:p@example.com/sentry/1")
if client.url != "https://example.com/sentry/api/1/store/" {
t.Error("incorrect url:", client.url)
}
if client.projectID != "1" {
t.Error("incorrect projectID:", client.projectID)
}
if client.authHeader != "Sentry sentry_version=4, sentry_key=u, sentry_secret=p" {
t.Error("incorrect authHeader:", client.authHeader)
}
}
func TestNewClient(t *testing.T) {
client := newClient(nil)
if client.sampleRate != 1.0 {
t.Error("invalid default sample rate")
}
}
func TestSetSampleRate(t *testing.T) {
client := &Client{}
err := client.SetSampleRate(0.2)
if err != nil {
t.Error("invalid sample rate")
}
if client.sampleRate != 0.2 {
t.Error("incorrect sample rate: ", client.sampleRate)
}
}
func TestSetSampleRateInvalid(t *testing.T) {
client := &Client{}
err := client.SetSampleRate(-1.0)
if err != ErrInvalidSampleRate {
t.Error("invalid sample rate should return ErrInvalidSampleRate")
}
}
func TestUnmarshalTag(t *testing.T) {
actual := new(Tag)
if err := json.Unmarshal([]byte(`["foo","bar"]`), actual); err != nil {
t.Fatal("unable to decode JSON:", err)
}
expected := &Tag{Key: "foo", Value: "bar"}
if !reflect.DeepEqual(actual, expected) {
t.Errorf("incorrect Tag: wanted '%+v' and got '%+v'", expected, actual)
}
}
func TestUnmarshalTags(t *testing.T) {
tests := []struct {
Input string
Expected Tags
}{
{
`{"foo":"bar"}`,
Tags{Tag{Key: "foo", Value: "bar"}},
},
{
`[["foo","bar"],["bar","baz"]]`,
Tags{Tag{Key: "foo", Value: "bar"}, Tag{Key: "bar", Value: "baz"}},
},
}
for _, test := range tests {
var actual Tags
if err := json.Unmarshal([]byte(test.Input), &actual); err != nil {
t.Fatal("unable to decode JSON:", err)
}
if !reflect.DeepEqual(actual, test.Expected) {
t.Errorf("incorrect Tags: wanted '%+v' and got '%+v'", test.Expected, actual)
}
}
}
func TestMarshalTimestamp(t *testing.T) {
timestamp := Timestamp(time.Date(2000, 01, 02, 03, 04, 05, 0, time.UTC))
expected := `"2000-01-02T03:04:05.00"`
actual, err := json.Marshal(timestamp)
if err != nil {
t.Error(err)
}
if string(actual) != expected {
t.Errorf("incorrect string; got %s, want %s", actual, expected)
}
}
func TestUnmarshalTimestamp(t *testing.T) {
timestamp := `"2000-01-02T03:04:05.00"`
expected := Timestamp(time.Date(2000, 01, 02, 03, 04, 05, 0, time.UTC))
var actual Timestamp
err := json.Unmarshal([]byte(timestamp), &actual)
if err != nil {
t.Error(err)
}
if actual != expected {
t.Errorf("incorrect string; got %s, want %s", actual.Format("2006-01-02 15:04:05 -0700"), expected.Format("2006-01-02 15:04:05 -0700"))
}
}
func TestNilClient(t *testing.T) {
var client *Client = nil
eventID, ch := client.Capture(nil, nil)
if eventID != "" {
t.Error("expected empty eventID:", eventID)
}
// wait on ch: no send should succeed immediately
err := <-ch
if err != nil {
t.Error("expected nil err:", err)
}
}
func TestCaptureNil(t *testing.T) {
var client *Client = DefaultClient
eventID, ch := client.Capture(nil, nil)
if eventID != "" {
t.Error("expected empty eventID:", eventID)
}
// wait on ch: no send should succeed immediately
err := <-ch
if err != nil {
t.Error("expected nil err:", err)
}
}
func TestCaptureNilError(t *testing.T) {
var client *Client = DefaultClient
eventID := client.CaptureError(nil, nil)
if eventID != "" {
t.Error("expected empty eventID:", eventID)
}
}
func TestNewPacketWithExtraSetsDefault(t *testing.T) {
testCases := []struct {
Extra Extra
Expected Extra
}{
// Defaults should be set when nil is passed
{
Extra: nil,
Expected: setExtraDefaults(Extra{}),
},
// Defaults should be set when empty is passed
{
Extra: Extra{},
Expected: setExtraDefaults(Extra{}),
},
// Packet should always override default keys
{
Extra: Extra{
"runtime.Version": "notagoversion",
},
Expected: setExtraDefaults(Extra{}),
},
// Packet should include our extra info
{
Extra: Extra{
"extra.extra": "extra",
},
Expected: setExtraDefaults(Extra{
"extra.extra": "extra",
}),
},
}
for i, test := range testCases {
packet := NewPacketWithExtra("packet", test.Extra)
if !reflect.DeepEqual(packet.Extra, test.Expected) {
t.Errorf("Case [%d]: Expected packet: %+v, got: %+v", i, test.Expected, packet.Extra)
}
}
}

View File

@@ -1,153 +0,0 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/raven-js.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/raven-js.qhc"
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/raven-js"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/raven-js"
@echo "# devhelp"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

View File

@@ -1,248 +0,0 @@
# -*- coding: utf-8 -*-
#
# raven-go documentation build configuration file, created by
# sphinx-quickstart on Mon Jan 21 21:04:27 2013.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os, datetime
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration -----------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'raven-go'
copyright = u'%s, Functional Software Inc.' % datetime.date.today().year
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The full version, including alpha/beta/rc tags.
release = '0.0.0'
# The short X.Y version.
version = release.rsplit('.', 1)[0]
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['_build']
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'raven-godoc'
# -- Options for LaTeX output --------------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#'preamble': '',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'raven-go.tex', u'raven-go Documentation',
u'Functional Software Inc.', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
#latex_show_urls = False
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_domain_indices = True
# -- Options for manual page output --------------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
('index', 'raven-go', u'raven-go Documentation',
[u'Functional Software Inc.'], 1)
]
# If true, show URL addresses after external links.
#man_show_urls = False
# -- Options for Texinfo output ------------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
('index', 'raven-go', u'raven-go Documentation',
u'Functional Software Inc.', 'raven-go', 'One line description of project.',
'Miscellaneous'),
]
# Documents to append as an appendix to all manuals.
#texinfo_appendices = []
# If false, no module index is generated.
#texinfo_domain_indices = True
# How to display URL addresses: 'footnote', 'no', or 'inline'.
#texinfo_show_urls = 'footnote'
if os.environ.get('SENTRY_FEDERATED_DOCS') != '1':
sys.path.insert(0, os.path.abspath('_sentryext'))
import sentryext
sentryext.activate()

View File

@@ -1,121 +0,0 @@
.. sentry:edition:: self
Raven Go
========
.. sentry:edition:: hosted, on-premise
.. class:: platform-go
Go
==
.. sentry:support-warning::
The Go SDK is maintained and supported by Sentry but currently
under development. Learn more about the project on `GitHub
<https://github.com/getsentry/raven-go>`__.
Raven-Go provides a Sentry client implementation for the Go programming
language.
Installation
------------
Raven-Go can be installed like any other Go library through ``go get``::
$ go get github.com/getsentry/raven-go
Configuring the Client
----------------------
To use ``raven-go``, you'll need to import the ``raven`` package, then initilize your
DSN globally. If you specify the ``SENTRY_DSN`` environment variable, this will be
done automatically for you. The release and environment can also be specified in the
environment variables ``SENTRY_RELEASE`` and ``SENTRY_ENVIRONMENT`` respectively.
.. sourcecode:: go
package main
import "github.com/getsentry/raven-go"
func init() {
raven.SetDSN("___DSN___")
}
Reporting Errors
----------------
In Go, there are both errors and panics, and Raven can handle both. To learn more
about the differences, please read `Error handling and Go <https://blog.golang.org/error-handling-and-go>`_.
To handle normal ``error`` responses, we have two options: ``CaptureErrorAndWait`` and ``CaptureError``. The former is a blocking call, for a case where you'd like to exit the application after reporting, and the latter is non-blocking.
.. sourcecode:: go
f, err := os.Open("filename.ext")
if err != nil {
raven.CaptureErrorAndWait(err, nil)
log.Panic(err)
}
Reporting Panics
----------------
Capturing a panic is pretty simple as well. We just need to wrap our code in ``CapturePanic``. ``CapturePanic`` will execute the ``func`` and if a panic happened, we will record it, and gracefully continue.
.. sourcecode:: go
raven.CapturePanic(func() {
// do all of the scary things here
}, nil)
Additional Context
------------------
All of the ``Capture*`` functions accept an additional argument for passing a ``map`` of tags
as the second argument. For example:
.. sourcecode:: go
raven.CaptureError(err, map[string]string{"browser": "Firefox"})
Tags in Sentry help to categories and give you more information about the errors that happened.
Event Sampling
--------------------
To setup client side sampling you can use ``SetSampleRate`` Client function.
Error sampling is disabled by default (sampleRate=1).
.. sourcecode:: go
package main
import "github.com/getsentry/raven-go"
func init() {
raven.SetSampleRate(0.25)
}
Deep Dive
---------
For more detailed information about how to get the most out of ``raven-go`` there
is additional documentation available that covers all the rest:
.. toctree::
:maxdepth: 2
:titlesonly:
integrations/index
Resources:
* `Bug Tracker <https://github.com/getsentry/raven-go/issues>`_
* `GitHub Project <https://github.com/getsentry/raven-go>`_
* `Godocs <https://godoc.org/github.com/getsentry/raven-go>`_

View File

@@ -1,41 +0,0 @@
net/http
========
Raven Go provides middleware that can be used with the stdlib ``net/http`` library to
automatically handle panics that occur during an http request.
Installation
------------
Simply install ``raven-go`` through ``go get``::
$ go get github.com/getsentry/raven-go
Setup
-----
Make sure that you've set configured ``raven`` with your DSN, typically inside the ``init()``
in your ``main`` package is a good place.
.. sourcecode:: go
package main
import "github.com/getsentry/raven-go"
func init() {
raven.SetDSN("___DSN___")
}
If you don't call ``SetDSN``, we will attempt to read it from your environment under the
``SENTRY_DSN`` environment variable. The release and environment will also be read from
the environment variables ``SENTRY_RELEASE`` and ``SENTRY_ENVIRONMENT`` if set.
Next, we need to wrap our ``http.Handler`` with our ``RecoveryHandler``:
.. sourcecode:: go
func root(w http.ResponseWriter, r *http.Request) {
// ... do stuff
}
http.HandleFunc("/", raven.RecoveryHandler(root))

View File

@@ -1,10 +0,0 @@
Integrations
============
The Raven Go package currently comes with an integration for the native ``net/http`` module
to make it easy to handle common scenarios. More frameworks will be coming soon.
.. toctree::
:maxdepth: 1
http

View File

@@ -1,190 +0,0 @@
@ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^<target^>` where ^<target^> is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\raven-js.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\raven-js.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
:end

View File

@@ -1,25 +0,0 @@
{
"support_level": "in-development",
"platforms": {
"go": {
"name": "Go",
"type": "language",
"doc_link": "",
"wizard": [
"index#installation",
"index#configuring-the-client",
"index#reporting-errors",
"index#reporting-panics"
]
},
"go.http": {
"name": "net/http",
"type": "framework",
"doc_wizard": "integrations/http/",
"wizard": [
"integrations/http#installation",
"integrations/http#setup"
]
}
}
}

View File

@@ -1,144 +0,0 @@
package raven
import (
"fmt"
"reflect"
"testing"
pkgErrors "github.com/pkg/errors"
)
func TestWrapWithExtraGeneratesProperErrWithExtra(t *testing.T) {
errMsg := "This is bad"
baseErr := fmt.Errorf(errMsg)
extraInfo := map[string]interface{}{
"string": "string",
"int": 1,
"float": 1.001,
"bool": false,
}
testErr := WrapWithExtra(baseErr, extraInfo)
wrapped, ok := testErr.(ErrWithExtra)
if !ok {
t.Errorf("Wrapped error does not conform to expected protocol.")
}
if !reflect.DeepEqual(wrapped.Cause(), baseErr) {
t.Errorf("Failed to unwrap error, got %+v, expected %+v", wrapped.Cause(), baseErr)
}
returnedExtra := wrapped.ExtraInfo()
for expectedKey, expectedVal := range extraInfo {
val, ok := returnedExtra[expectedKey]
if !ok {
t.Errorf("Extra data missing key: %s", expectedKey)
}
if val != expectedVal {
t.Errorf("Extra data [%s]: Got: %+v, expected: %+v", expectedKey, val, expectedVal)
}
}
if wrapped.Error() != errMsg {
t.Errorf("Wrong error message, got: %q, expected: %q", wrapped.Error(), errMsg)
}
}
func TestWrapWithExtraGeneratesCausableError(t *testing.T) {
baseErr := fmt.Errorf("this is bad")
testErr := WrapWithExtra(baseErr, nil)
cause := pkgErrors.Cause(testErr)
if !reflect.DeepEqual(cause, baseErr) {
t.Errorf("Failed to unwrap error, got %+v, expected %+v", cause, baseErr)
}
}
func TestExtractErrorPullsExtraData(t *testing.T) {
extraInfo := map[string]interface{}{
"string": "string",
"int": 1,
"float": 1.001,
"bool": false,
}
emptyInfo := map[string]interface{}{}
testCases := []struct {
Error error
Expected map[string]interface{}
}{
// Unwrapped error shouldn't include anything
{
Error: fmt.Errorf("This is bad"),
Expected: emptyInfo,
},
// Wrapped error with nil map should extract as empty info
{
Error: WrapWithExtra(fmt.Errorf("This is bad"), nil),
Expected: emptyInfo,
},
// Wrapped error with empty map should extract as empty info
{
Error: WrapWithExtra(fmt.Errorf("This is bad"), emptyInfo),
Expected: emptyInfo,
},
// Wrapped error with extra info should extract with all data
{
Error: WrapWithExtra(fmt.Errorf("This is bad"), extraInfo),
Expected: extraInfo,
},
// Nested wrapped error should extract all the info
{
Error: WrapWithExtra(
WrapWithExtra(fmt.Errorf("This is bad"),
map[string]interface{}{
"inner": "123",
}),
map[string]interface{}{
"outer": "456",
},
),
Expected: map[string]interface{}{
"inner": "123",
"outer": "456",
},
},
// Futher wrapping of errors shouldn't allow for value override
{
Error: WrapWithExtra(
WrapWithExtra(fmt.Errorf("This is bad"),
map[string]interface{}{
"dontoverride": "123",
}),
map[string]interface{}{
"dontoverride": "456",
},
),
Expected: map[string]interface{}{
"dontoverride": "123",
},
},
}
for i, test := range testCases {
extracted := extractExtra(test.Error)
if len(test.Expected) != len(extracted) {
t.Errorf(
"Case [%d]: Mismatched amount of data between provided and extracted extra. Got: %+v Expected: %+v",
i,
extracted,
test.Expected,
)
}
for expectedKey, expectedVal := range test.Expected {
val, ok := extracted[expectedKey]
if !ok {
t.Errorf("Case [%d]: Extra data missing key: %s", i, expectedKey)
}
if val != expectedVal {
t.Errorf("Case [%d]: Wrong extra data for %q. Got: %+v, expected: %+v", i, expectedKey, val, expectedVal)
}
}
}
}

View File

@@ -1,42 +0,0 @@
package main
import (
"errors"
"fmt"
"github.com/getsentry/raven-go"
"log"
"net/http"
"os"
)
func trace() *raven.Stacktrace {
return raven.NewStacktrace(0, 2, nil)
}
func main() {
client, err := raven.NewWithTags(os.Args[1], map[string]string{"foo": "bar"})
if err != nil {
log.Fatal(err)
}
httpReq, _ := http.NewRequest("GET", "http://example.com/foo?bar=true", nil)
httpReq.RemoteAddr = "127.0.0.1:80"
httpReq.Header = http.Header{"Content-Type": {"text/html"}, "Content-Length": {"42"}}
packet := &raven.Packet{Message: "Test report", Interfaces: []raven.Interface{raven.NewException(errors.New("example"), trace()), raven.NewHttp(httpReq)}}
_, ch := client.Capture(packet, nil)
if err = <-ch; err != nil {
log.Fatal(err)
}
log.Print("sent packet successfully")
}
// CheckError sends error report to sentry and records event id and error name to the logs
func CheckError(err error, r *http.Request) {
client, err := raven.NewWithTags(os.Args[1], map[string]string{"foo": "bar"})
if err != nil {
log.Fatal(err)
}
packet := raven.NewPacket(err.Error(), raven.NewException(err, trace()), raven.NewHttp(r))
eventID, _ := client.Capture(packet, nil)
message := fmt.Sprintf("Error event with id \"%s\" - %s", eventID, err.Error())
log.Println(message)
}

View File

@@ -1,28 +0,0 @@
package raven
import (
"fmt"
"log"
"net/http"
)
func Example() {
// ... i.e. raisedErr is incoming error
var raisedErr error
// sentry DSN generated by Sentry server
var sentryDSN string
// r is a request performed when error occured
var r *http.Request
client, err := New(sentryDSN)
if err != nil {
log.Fatal(err)
}
trace := NewStacktrace(0, 2, nil)
packet := NewPacket(raisedErr.Error(), NewException(raisedErr, trace), NewHttp(r))
eventID, ch := client.Capture(packet, nil)
if err = <-ch; err != nil {
log.Fatal(err)
}
message := fmt.Sprintf("Captured error with id %s: %q", eventID, raisedErr)
log.Println(message)
}

View File

@@ -1,39 +0,0 @@
package raven
import (
"encoding/json"
"errors"
"testing"
)
var newExceptionTests = []struct {
err error
Exception
}{
{errors.New("foobar"), Exception{Value: "foobar", Type: "*errors.errorString"}},
{errors.New("bar: foobar"), Exception{Value: "foobar", Type: "*errors.errorString", Module: "bar"}},
}
func TestNewException(t *testing.T) {
for _, test := range newExceptionTests {
actual := NewException(test.err, nil)
if actual.Value != test.Value {
t.Errorf("incorrect Value: got %s, want %s", actual.Value, test.Value)
}
if actual.Type != test.Type {
t.Errorf("incorrect Type: got %s, want %s", actual.Type, test.Type)
}
if actual.Module != test.Module {
t.Errorf("incorrect Module: got %s, want %s", actual.Module, test.Module)
}
}
}
func TestNewException_JSON(t *testing.T) {
expected := `{"value":"foobar","type":"*errors.errorString"}`
e := NewException(errors.New("foobar"), nil)
b, _ := json.Marshal(e)
if string(b) != expected {
t.Errorf("incorrect JSON: got %s, want %s", string(b), expected)
}
}

View File

@@ -1,150 +0,0 @@
package raven
import (
"net/http"
"net/url"
"reflect"
"testing"
)
type testcase struct {
request *http.Request
*Http
}
func newBaseRequest() *http.Request {
u, _ := url.Parse("http://example.com/")
header := make(http.Header)
header.Add("Foo", "bar")
req := &http.Request{
Method: "GET",
URL: u,
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
Header: header,
Host: u.Host,
RemoteAddr: "127.0.0.1:8000",
}
return req
}
func newBaseHttp() *Http {
h := &Http{
Method: "GET",
Cookies: "",
Query: "",
URL: "http://example.com/",
Headers: map[string]string{"Foo": "bar"},
Env: map[string]string{"REMOTE_ADDR": "127.0.0.1", "REMOTE_PORT": "8000"},
}
h.Headers["Host"] = "example.com"
return h
}
func NewRequest() testcase {
return testcase{newBaseRequest(), newBaseHttp()}
}
func NewRequestIPV6() testcase {
req := newBaseRequest()
req.RemoteAddr = "[:1]:8000"
h := newBaseHttp()
h.Env = map[string]string{"REMOTE_ADDR": ":1", "REMOTE_PORT": "8000"}
return testcase{req, h}
}
func NewRequestMultipleHeaders() testcase {
req := newBaseRequest()
req.Header.Add("Foo", "baz")
h := newBaseHttp()
h.Headers["Foo"] = "bar,baz"
return testcase{req, h}
}
func NewSecureRequest() testcase {
req := newBaseRequest()
req.Header.Add("X-Forwarded-Proto", "https")
h := newBaseHttp()
h.URL = "https://example.com/"
h.Headers["X-Forwarded-Proto"] = "https"
return testcase{req, h}
}
func NewCookiesRequest() testcase {
val := "foo=bar; bar=baz"
req := newBaseRequest()
req.Header.Add("Cookie", val)
h := newBaseHttp()
h.Cookies = val
h.Headers["Cookie"] = val
return testcase{req, h}
}
var newHttpTests = []testcase{
NewRequest(),
NewRequestIPV6(),
NewRequestMultipleHeaders(),
NewSecureRequest(),
NewCookiesRequest(),
}
func TestNewHttp(t *testing.T) {
for _, test := range newHttpTests {
actual := NewHttp(test.request)
if actual.Method != test.Method {
t.Errorf("incorrect Method: got %s, want %s", actual.Method, test.Method)
}
if actual.Cookies != test.Cookies {
t.Errorf("incorrect Cookies: got %s, want %s", actual.Cookies, test.Cookies)
}
if actual.Query != test.Query {
t.Errorf("incorrect Query: got %s, want %s", actual.Query, test.Query)
}
if actual.URL != test.URL {
t.Errorf("incorrect URL: got %s, want %s", actual.URL, test.URL)
}
if !reflect.DeepEqual(actual.Headers, test.Headers) {
t.Errorf("incorrect Headers: got %+v, want %+v", actual.Headers, test.Headers)
}
if !reflect.DeepEqual(actual.Env, test.Env) {
t.Errorf("incorrect Env: got %+v, want %+v", actual.Env, test.Env)
}
if !reflect.DeepEqual(actual.Data, test.Data) {
t.Errorf("incorrect Data: got %+v, want %+v", actual.Data, test.Data)
}
}
}
var sanitizeQueryTests = []struct {
input, output string
}{
{"foo=bar", "foo=bar"},
{"password=foo", "password=********"},
{"passphrase=foo", "passphrase=********"},
{"passwd=foo", "passwd=********"},
{"secret=foo", "secret=********"},
{"secretstuff=foo", "secretstuff=********"},
{"foo=bar&secret=foo", "foo=bar&secret=********"},
{"secret=foo&secret=bar", "secret=********"},
}
func parseQuery(q string) url.Values {
r, _ := url.ParseQuery(q)
return r
}
func TestSanitizeQuery(t *testing.T) {
for _, test := range sanitizeQueryTests {
actual := sanitizeQuery(parseQuery(test.input))
expected := parseQuery(test.output)
if !reflect.DeepEqual(actual, expected) {
t.Errorf("incorrect sanitization: got %+v, want %+v", actual, expected)
}
}
}

View File

@@ -1,188 +0,0 @@
package raven
import (
"fmt"
"go/build"
"io/ioutil"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
)
type FunctionNameTest struct {
skip int
pack string
name string
}
var (
thisFile string
thisPackage string
functionNameTests []FunctionNameTest
)
func TestFunctionName(t *testing.T) {
for _, test := range functionNameTests {
pc, _, _, _ := runtime.Caller(test.skip)
pack, name := functionName(pc)
if pack != test.pack {
t.Errorf("incorrect package; got %s, want %s", pack, test.pack)
}
if name != test.name {
t.Errorf("incorrect function; got %s, want %s", name, test.name)
}
}
}
func TestStacktrace(t *testing.T) {
st := trace()
if st == nil {
t.Error("got nil stacktrace")
}
if len(st.Frames) == 0 {
t.Error("got zero frames")
}
f := st.Frames[len(st.Frames)-1]
if f.Filename != thisFile {
t.Errorf("incorrect Filename; got %s, want %s", f.Filename, thisFile)
}
if !strings.HasSuffix(f.AbsolutePath, thisFile) {
t.Error("incorrect AbsolutePath:", f.AbsolutePath)
}
if f.Function != "trace" {
t.Error("incorrect Function:", f.Function)
}
if f.Module != thisPackage {
t.Error("incorrect Module:", f.Module)
}
if f.Lineno != 87 {
t.Error("incorrect Lineno:", f.Lineno)
}
if f.ContextLine != "\treturn NewStacktrace(0, 2, []string{thisPackage})" {
t.Errorf("incorrect ContextLine: %#v", f.ContextLine)
}
if len(f.PreContext) != 2 || f.PreContext[0] != "// a" || f.PreContext[1] != "func trace() *Stacktrace {" {
t.Errorf("incorrect PreContext %#v", f.PreContext)
}
if len(f.PostContext) != 2 || f.PostContext[0] != "\t// b" || f.PostContext[1] != "}" {
t.Errorf("incorrect PostContext %#v", f.PostContext)
}
_, filename, _, _ := runtime.Caller(0)
runningInVendored := strings.Contains(filename, "vendor")
if f.InApp != !runningInVendored {
t.Error("expected InApp to be true")
}
if f.InApp && st.Culprit() != fmt.Sprintf("%s.trace", thisPackage) {
t.Error("incorrect Culprit:", st.Culprit())
}
}
// a
func trace() *Stacktrace {
return NewStacktrace(0, 2, []string{thisPackage})
// b
}
func derivePackage() (file, pack string) {
// Get file name by seeking caller's file name.
_, callerFile, _, ok := runtime.Caller(1)
if !ok {
return
}
// Trim file name
file = callerFile
for _, dir := range build.Default.SrcDirs() {
dir := dir + string(filepath.Separator)
if trimmed := strings.TrimPrefix(callerFile, dir); len(trimmed) < len(file) {
file = trimmed
}
}
// Now derive package name
dir := filepath.Dir(callerFile)
dirPkg, err := build.ImportDir(dir, build.AllowBinary)
if err != nil {
return
}
pack = dirPkg.ImportPath
return
}
func init() {
thisFile, thisPackage = derivePackage()
functionNameTests = []FunctionNameTest{
{0, thisPackage, "TestFunctionName"},
{1, "testing", "tRunner"},
{2, "runtime", "goexit"},
{100, "", ""},
}
}
// TestNewStacktrace_outOfBounds verifies that a context exceeding the number
// of lines in a file does not cause a panic.
func TestNewStacktrace_outOfBounds(t *testing.T) {
st := NewStacktrace(0, 1000000, []string{thisPackage})
f := st.Frames[len(st.Frames)-1]
if f.ContextLine != "\tst := NewStacktrace(0, 1000000, []string{thisPackage})" {
t.Errorf("incorrect ContextLine: %#v", f.ContextLine)
}
}
func TestNewStacktrace_noFrames(t *testing.T) {
st := NewStacktrace(999999999, 0, []string{})
if st != nil {
t.Errorf("expected st.Frames to be nil: %v", st)
}
}
func TestFileContext(t *testing.T) {
// reset the cache
fileCache = make(map[string][][]byte)
tempdir, err := ioutil.TempDir("", "")
if err != nil {
t.Fatal("failed to create temporary directory:", err)
}
defer os.RemoveAll(tempdir)
okPath := filepath.Join(tempdir, "ok")
missingPath := filepath.Join(tempdir, "missing")
noPermissionPath := filepath.Join(tempdir, "noperms")
err = ioutil.WriteFile(okPath, []byte("hello\nworld\n"), 0600)
if err != nil {
t.Fatal("failed writing file:", err)
}
err = ioutil.WriteFile(noPermissionPath, []byte("no access\n"), 0000)
if err != nil {
t.Fatal("failed writing file:", err)
}
tests := []struct {
path string
expectedLines int
expectedIndex int
}{
{okPath, 1, 0},
{missingPath, 0, 0},
{noPermissionPath, 0, 0},
}
for i, test := range tests {
lines, index := fileContext(test.path, 1, 0)
if !(len(lines) == test.expectedLines && index == test.expectedIndex) {
t.Errorf("%d: fileContext(%#v, 1, 0) = %v, %v; expected len()=%d, %d",
i, test.path, lines, index, test.expectedLines, test.expectedIndex)
}
if len(fileCache) != i+1 {
t.Errorf("%d: result was not cached; len(fileCached)=%d", i, len(fileCache))
}
}
}