Skip to content

Commit

Permalink
Add CI (#3)
Browse files Browse the repository at this point in the history
* add CI

* CI update

* ci update

* ci update

* ci update

* ci update

* CI update

* CI update

* add more unit tests

* fix test

* CI update

* CI fix formating

Co-authored-by: bjankulovski <bjankulovski@mediaresources.com>
  • Loading branch information
boseca and bjankulovski committed Jun 5, 2022
1 parent 3d57105 commit 2cd33c6
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 7 deletions.
42 changes: 42 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# This workflow will run test and upload the coverage when push or pull_request is made on `dev` branch
name: build

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

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.15

- name: Checkout the code
uses: actions/checkout@v2
with:
fetch-depth: 2

- name: Get dependencies
run: |
go get -v -t -d ./...
- name: Run Test and get coverage
run: |
go test -race -covermode atomic -coverprofile=covprofile
sed -i "s/$(pwd|sed 's/\//\\\//g')/./g" covprofile # convert absolute path to relative path
- name: Push test coverage
if: success()
continue-on-error: true
uses: shogo82148/actions-goveralls@v1
with:
path-to-profile: covprofile

18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
RawEml
=========
This is a wrapper for the AWS SES raw email and allows to set the message priority and the conversation topic to group emails with same topic.
This package is for a granual control of emails that are sent with AWS SES.
It supports setting the email priority, conversation topic for grouping and any other email header tags.

[![Build Status](https://github.com/boseca/raweml/workflows/build/badge.svg)](https://github.com/boseca/raweml/actions?query=workflow%3Abuild)
[![Coverage Status](https://coveralls.io/repos/github/boseca/raweml/badge.svg?branch=master)](https://coveralls.io/github/boseca/raweml?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/boseca/raweml)](https://goreportcard.com/report/github.com/boseca/raweml)
[![Documentation](https://godoc.org/gopkg.in/raweml?status.svg)](https://godoc.org/gopkg.in/raweml)

## Description

Expand Down Expand Up @@ -75,3 +81,13 @@ go test -v ./example
```bash
golint
```

- Show code coverage
```bash
go test -coverprofile=c.out
sed -i "s/$(pwd|sed 's/\//\\\//g')/./g" c.out # convert absolute path to relative path
go tool cover -html=c.out -o=c.html # optional
gcov2lcov -infile=c.out -outfile=c.lcov
genhtml -q --legend -o coverage_html --title='Raweml' c.lcov
x-www-browser file:///$(pwd)/coverage_html/index.html
```
14 changes: 13 additions & 1 deletion raweml.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"net/textproto"
"os"
"path/filepath"
"sort"
"strings"

"github.com/aws/aws-sdk-go/aws"
Expand Down Expand Up @@ -391,7 +392,9 @@ func addAttachments(w io.Writer, attachments []Attachment, boundary string) erro
// Header values will be trimmed but otherwise left alone.
// Headers with multiple values are not supported and will return an error.
func writeHeader(w io.Writer, header *textproto.MIMEHeader) error {
for k, vs := range *header {
// for k, vs := range *header {
for _, k := range sortedHeaders(header) {
vs := header.Values(k)
_, err := fmt.Fprintf(w, "%s: ", k)
if err != nil {
return err
Expand Down Expand Up @@ -468,6 +471,15 @@ func (priority EmailPriority) String() string {
return string(priority)
}

func sortedHeaders(header *textproto.MIMEHeader) (keys []string) {
// type MIMEHeader map[string][]string
for k := range *header {
keys = append(keys, k)
}
sort.Strings(keys)
return keys
}

// func win32TimeFromTar(key string, hdrs map[string]string, unixTime time.Time) Filetime {
// if s, ok := hdrs[key]; ok {
// n, err := strconv.ParseUint(s, 10, 64)
Expand Down
120 changes: 120 additions & 0 deletions raweml_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package raweml

import (
"strings"
"testing"
)

// ---------------------------------------------------------------
// # TODO - create test for raweml
// ---------------------------------------------------------------
// - add test for `raweml` (test for GetSendRawEmailInput and NewRecipients)
// ---------------------------------------------------------------
var (
testEmailString = `Content-Language: en-US
Content-Type: multipart/mixed; boundary=*
From: NO REPLAY EMAIL ACCOUNT <no-reply@example.com>
Mime-Version: 1.0
References: MbfJRQw5X+qg8GSOJxjM2Q==
Subject: Simple Test
Thread-Index: *
Thread-Topic: Hello world
To: customer@example.com
X-Priority: 3
*
Content-Type: multipart/alternative; boundary=*
Mime-Version: 1.0
*
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset=UTF-8
Amazon SES Test Email (AWS SDK for Go)
*
Content-Transfer-Encoding: 7bit
Content-Type: text/html; charset=UTF-8
<h1>Amazon SES Test Email (AWS SDK for Go)</h1>
*
*
*
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64
Content-ID: <1001>
X-Attachment-Id: 1001
Content-Disposition: attachment; filename="Mars.png"
*`
)

func TestRaweml(t *testing.T) {
t.Run("Test conversion of Email to raw data", func(t *testing.T) {
// create Email
const fromEmail = "NO REPLAY EMAIL ACCOUNT <no-reply@example.com>"
eml := Email{
From: fromEmail,
Recipients: NewRecipients("customer@example.com", "", ""),
Subject: "Simple Test",
TextBody: "Amazon SES Test Email (AWS SDK for Go)",
HTMLBody: "<h1>Amazon SES Test Email (AWS SDK for Go)</h1>",
Topic: "Hello world",
Attachments: []Attachment{{Name: "example/Mars.png", ContentID: "1001"}},
AwsRegion: "us-east-1",
}
eml.SetHeader("X-something", "test")

// get Email Raw data
r, err := eml.GetSendRawEmailInput()
if err != nil {
t.Error(err)
}

// validate the email
if got := eml.GetSource(); *got != fromEmail {
t.Errorf("Invalid Source!\nwant:%s\ngot:%s", fromEmail, *got)
}
if want := "customer@example.com"; *r.Destinations[0] != want {
t.Errorf("Invalid destination!\nwant:%v\ngot:%v", want, r.Destinations)
}

// line by line comparison
str := strings.Split(strings.ReplaceAll(string(r.RawMessage.Data), "\r", ""), "\n")
for i, line := range strings.Split(testEmailString, "\n") {
if line != "*" {
if strings.HasSuffix(line, "*") || strings.HasSuffix(line, "*\r") {
// compare first part
max := len(line) - 1
if strings.HasSuffix(line, "*\r") {
max = max - 1
}
if str[i][0:max] != line[0:max] {
t.Errorf("Invalid RawMessage data line with wildchar! (%v)\nwant:%s\ngot:%s", i, line, str[i])
}
} else {
if str[i] != line {
t.Errorf("Invalid RawMessage data line! (%v)\nwant:%s\ngot:%s", i, line, str[i])
}
}
}
}
})
t.Run("Test New Recipients", func(t *testing.T) {
to := "to_1@h.com,to_2@h.com"
cc := "cc_1@h.com,c_2@h.com"
bcc := "bcc_1@h.com,bcc_2@h.com"
email := Email{
Recipients: NewRecipients(to, cc, bcc),
}

// var want []*string
// for _, v := range strings.Split(to+","+cc+","+bcc, ",") {
// want = append(want, &v)
// }
want := to + "," + cc + "," + bcc
got := email.Recipients.String()
if want != got {
t.Errorf("Invalid Recipients!\nwant:%s\ngot:%s", want, got)
}
})
}
6 changes: 1 addition & 5 deletions thread.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,18 +373,14 @@ func unixToTimeStamp64(unixNanosecond int64) int64 {
return unixNanosecond/100 + 116444736000000000
}

// unixToTimeStamp converts unix time to time stamp uint64
func unixToTimeStamp(unixNanosecond uint64) uint64 {
return unixNanosecond/100 + 116444736000000000
}

// Helping functions (private)

func int64ToBytes(num int64) []byte {
b := make([]byte, 8)
binary.BigEndian.PutUint64(b, uint64(num))
return b
}

func bytesToInt64(b []byte) int64 {
return int64(binary.BigEndian.Uint64(b))
}
38 changes: 38 additions & 0 deletions thread_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package raweml

import (
"bytes"
"encoding/base64"
"encoding/hex"
"fmt"
Expand Down Expand Up @@ -266,6 +267,43 @@ func TestThread(t *testing.T) {
}
}
})
t.Run("Test New Thread", func(t *testing.T) {
thread := NewThread("Hello world")
thread.AddChildBlock()
want := thread.Bytes()
threadParm := NewEmailThreadFromParams(thread.DateUnixNano, thread.GetGUID(), thread.GetTopic(), thread.ChildBlocks)
got := threadParm.Bytes()
if bytes.Compare(got, want) != 0 {
t.Errorf("Invalid Filetime conversion!\ngot: %s\nwant: %s", got, want)
}
if got := thread.String(); got != thread.Index() {
t.Errorf("String does not match the index!\ngot: %s\nwant: %s", got, thread.Index())
}
if got := thread.Reference(); got != "MbfJRQw5X+qg8GSOJxjM2Q==" {
t.Errorf("Invalid reference!\ngot:%s\nwant:%s", got, "MbfJRQw5X+qg8GSOJxjM2Q==")
}
})
t.Run("Test converting Filetime to Unix nano seconds", func(t *testing.T) {
want := time.Now().UTC().UnixNano()
ft := UnixNanoToFiletime(want)
if got := ft.UnixNanoseconds(); got/100 != want/100 {
t.Errorf("Invalid Filetime conversion!\ngot: %v\nwant: %v", got, want)
}
})
t.Run("Test converting Bytes to Int", func(t *testing.T) {
want := int64(123456789)
b := int64ToBytes(want)
if got := bytesToInt64(b); got != want {
t.Errorf("Invalid bytes conversion!\ngot: %v\nwant: %v", got, want)
}
})
t.Run("Test conversion Hex to Base64", func(t *testing.T) {
b := []byte("hello world")
want := "aGVsbG8gd29ybGQ="
if got := hexToBase64(b); got != want {
t.Errorf("Invalid bytes conversion!\ngot: %v\nwant: %v", got, want)
}
})
}

// helping functions -----------------------
Expand Down

0 comments on commit 2cd33c6

Please sign in to comment.