Skip to content

Commit

Permalink
Merge pull request #3 from brainycodelab/setup-tests-and-ci
Browse files Browse the repository at this point in the history
chore: Setup CI and API tests
  • Loading branch information
damilolaedwards committed Oct 12, 2024
2 parents 28979ed + b4c59eb commit 623aca0
Show file tree
Hide file tree
Showing 8 changed files with 207 additions and 17 deletions.
40 changes: 40 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: Go CI

on:
push:
branches: [master]
pull_request:
branches: [master]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: '1.21'

- name: Check formatting
run: |
if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then
echo "The following files are not formatted correctly:"
gofmt -s -l .
exit 1
fi
- name: Get dependencies
run: go mod download

- name: Run go vet
run: go vet ./...

# - name: Run tests
# run: go test -v ./...

- name: Run golangci-lint
uses: golangci/golangci-lint-action@v3
with:
version: latest
3 changes: 3 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
linters:
disable:
- errcheck
16 changes: 8 additions & 8 deletions api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ import (
var staticAssets embed.FS

type API struct {
targetContracts string
contracts []types.Contract
logger *logging.Logger
projectName string
contractCodes string
contracts []types.Contract
logger *logging.Logger
projectName string
}

func InitializeAPI(contractCodes string, contracts []types.Contract) *API {
Expand All @@ -37,9 +37,9 @@ func InitializeAPI(contractCodes string, contracts []types.Contract) *API {
logger.AddWriter(os.Stdout, logging.UNSTRUCTURED, true)

return &API{
targetContracts: contractCodes,
contracts: contracts,
logger: logger,
contractCodes: contractCodes,
contracts: contracts,
logger: logger,
}
}

Expand Down Expand Up @@ -128,7 +128,7 @@ func (api *API) Start(projectConfig *config.ProjectConfig) {
}

func (api *API) attachRoutes(router *mux.Router) error {
return attachFrontendRoutes(router, api.contracts, api.targetContracts, api.projectName)
return attachFrontendRoutes(router, api.contracts, api.contractCodes, api.projectName)
}

func (api *API) attachMiddleware(router *mux.Router) {
Expand Down
142 changes: 142 additions & 0 deletions api/api_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package api

import (
"assistant/types"
"io"
"log"
"net/http"
"net/http/httptest"
"testing"

"github.com/gorilla/mux"
)

func TestInitializeAPI(t *testing.T) {
contracts := []types.Contract{{Name: "TestContract"}}
api := InitializeAPI("testContractCodes", contracts)

if api == nil {
t.Fatal("Expected non-nil API instance")
}

if api.contractCodes != "testContractCodes" {
t.Errorf("Expected targetContracts to be 'testContractCodes', got %s", api.contractCodes)
}

if len(api.contracts) != 1 || api.contracts[0].Name != "TestContract" {
t.Errorf("Expected contracts to contain one TestContract, got %v", api.contracts)
}

if api.logger == nil {
t.Error("Expected non-nil logger")
}
}

func TestAttachRoutes(t *testing.T) {
api := &API{
contractCodes: "testContracts",
contracts: []types.Contract{{Name: "TestContract"}},
projectName: "TestProject",
}

router := mux.NewRouter()
err := api.attachRoutes(router)

if err != nil {
t.Fatalf("attachRoutes returned an error: %v", err)
}

// Test that at least one route was attached by making a request
// and checking if it's handled (not resulting in a 404)
req, _ := http.NewRequest("GET", "/", nil)
rr := httptest.NewRecorder()
router.ServeHTTP(rr, req)

if rr.Code == http.StatusNotFound {
t.Error("Expected routes to be attached, but got a 404 response")
}
}

func TestAttachMiddleware(t *testing.T) {
api := &API{}
router := mux.NewRouter()

api.attachMiddleware(router)

// Create a test server using the router
server := httptest.NewServer(router)
defer server.Close()

// Send a request to the server
resp, err := http.Get(server.URL)
if err != nil {
t.Fatalf("Failed to send request: %v", err)
}
defer func(Body io.ReadCloser) {
err := Body.Close()
if err != nil {
log.Println("Error closing response body: ", err)
}
}(resp.Body)
}

func TestServeStaticFilesHandler(t *testing.T) {
// Create a request to /static/test.txt
req, err := http.NewRequest("GET", "/static/test.txt", nil)
if err != nil {
t.Fatal(err)
}

// Create a ResponseRecorder to record the response
rr := httptest.NewRecorder()

// Call the handler function
handler := http.HandlerFunc(serveStaticFilesHandler)
handler.ServeHTTP(rr, req)

// Check the status code
if status := rr.Code; status != http.StatusNotFound {
t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusNotFound)
}

// Send request for a file that exists
req, err = http.NewRequest("GET", "/static/css/style.css", nil)
if err != nil {
t.Fatal(err)
}

// Create a ResponseRecorder to record the response
rr = httptest.NewRecorder()

// Call the handler function
handler = http.HandlerFunc(serveStaticFilesHandler)
handler.ServeHTTP(rr, req)

// Check the status code
if status := rr.Code; status != http.StatusOK {
t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK)
}

// Check the content type
if contentType := rr.Header().Get("Content-Type"); contentType != "text/plain; charset=utf-8" {
t.Errorf("handler returned wrong content type: got %v want %v", contentType, "text/plain; charset=utf-8")
}
}

func TestIncrementPort(t *testing.T) {
testCases := []struct {
input string
expected string
}{
{":8080", ":8081"},
{":9000", ":9001"},
{":3000", ":3001"},
}

for _, tc := range testCases {
result := incrementPort(tc.input)
if result != tc.expected {
t.Errorf("incrementPort(%s) = %s; want %s", tc.input, result, tc.expected)
}
}
}
5 changes: 3 additions & 2 deletions api/services/conversation.service.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"assistant/llm"
"assistant/types"
"context"
"errors"
"fmt"
"sync"
)
Expand Down Expand Up @@ -38,7 +39,7 @@ func NewConversationService(targetContracts string) (*ConversationService, error
}

if numTokens > llm.GetDefaultModel().MaxTokenLen {
return nil, fmt.Errorf("target contracts exceed maximum token length")
return nil, errors.New("target contracts exceed maximum token length")
}

return &ConversationService{
Expand Down Expand Up @@ -98,7 +99,7 @@ func (ch *ConversationService) PromptLLM(ctx context.Context, prompt string, mod
func (ch *ConversationService) GenerateReport(ctx context.Context, data dto.GenerateReportDto, model string) ([]types.Message, error) {
sampleFileUrl, ok := ReportTypes[data.ReportType]
if !ok {
return nil, fmt.Errorf("invalid report type")
return nil, errors.New("invalid report type")
}

reportSample, err := client.FetchFileContent(sampleFileUrl, map[string]string{})
Expand Down
3 changes: 2 additions & 1 deletion cmd/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"assistant/config"
"assistant/internal/slither"
"assistant/logging/colors"
"errors"
"fmt"
"os"
"path/filepath"
Expand Down Expand Up @@ -37,7 +38,7 @@ func init() {
func cmdValidateStartArgs(cmd *cobra.Command, args []string) error {
// Make sure we have no positional args
if err := cobra.MaximumNArgs(1)(cmd, args); err != nil {
err = fmt.Errorf("start can only accept one positional argument, target contracts directory")
err = errors.New("start can only accept one positional argument, target contracts directory")
cmdLogger.Error("Failed to validate args to the start command", err)
return err
}
Expand Down
3 changes: 2 additions & 1 deletion internal/slither/slither.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"assistant/utils"
_ "embed"
"encoding/json"
"errors"
"fmt"
"log"
"os"
Expand Down Expand Up @@ -175,7 +176,7 @@ func ParseContracts(projectConfig *config.ProjectConfig) ([]types.Contract, stri
// Check if provided directory is a directory
info, err := os.Stat(projectConfig.TargetContracts.Dir)
if err != nil || !info.IsDir() {
return nil, "", fmt.Errorf("unable to read directory")
return nil, "", errors.New("unable to read directory")
}

slitherOutput, err = runSlitherOnLocal(projectConfig.TargetContracts.Dir, projectConfig.TargetContracts.ExcludePaths, projectConfig.TestContracts.Dir, projectConfig.TestContracts.ExcludePaths, projectConfig.SlitherArgs)
Expand Down
12 changes: 7 additions & 5 deletions llm/llm.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package llm
import (
"assistant/api/client"
"encoding/json"
"errors"
"fmt"
"golang.org/x/net/context"
"io"
"net/http"
"os"

"golang.org/x/net/context"
)

type Model struct {
Expand Down Expand Up @@ -76,7 +78,7 @@ func AskModel(messages []ApiMessage, model string, ctx context.Context) (string,
return "", err
}
if numTokens > m.MaxTokenLen {
return "", fmt.Errorf(TokenLimitExceeded)
return "", errors.New(TokenLimitExceeded)
}

var requestBody any
Expand Down Expand Up @@ -156,7 +158,7 @@ func handleImageResponse(body []byte) (string, error) {
if errorResponse.Error.Message != "" {
return "", fmt.Errorf("error: %s", errorResponse.Error.Message)
}
return "", fmt.Errorf("no response from model")
return "", errors.New("no response from model")
}

func handleOpenAITextResponse(body []byte) (string, error) {
Expand All @@ -177,7 +179,7 @@ func handleOpenAITextResponse(body []byte) (string, error) {
if errorResponse.Error.Message != "" {
return "", fmt.Errorf("error: %s", errorResponse.Error.Message)
}
return "", fmt.Errorf("no response from model")
return "", errors.New("no response from model")
}

func handleClaudeTextResponse(body []byte) (string, error) {
Expand All @@ -197,7 +199,7 @@ func handleClaudeTextResponse(body []byte) (string, error) {
if errorResponse.Error.Message != "" {
return "", fmt.Errorf("error: %s", errorResponse.Error.Message)
}
return "", fmt.Errorf("no response from model")
return "", errors.New("no response from model")
}

func GetDefaultModel() Model {
Expand Down

0 comments on commit 623aca0

Please sign in to comment.