Skip to content

Commit a1f0c2f

Browse files
Project Collection Build Service (51degrees)Project Collection Build Service (51degrees)
authored andcommitted
Merge pull request 6264 from hotfix/v4.3.2 into main
2 parents b852c78 + 7021327 commit a1f0c2f

16 files changed

+1601
-131
lines changed

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ This repository contains Go Lite implementation of device detection engine. This
1111
Go Lite implementation is currently supporting the following platforms and architectures:
1212
- Linux 32/64 bit, Intel and ARM processor
1313
- MacOS 64 bit, Intel and ARM processor
14+
- Windows 64bit, Intel
1415

1516
Go version:
1617
- 1.17.1
@@ -41,8 +42,8 @@ git lfs pull
4142
### Software
4243

4344
In order to build use device-detection-go the following are required:
44-
- Powershell Core
45-
- A C compiler that support C11 or above (Gcc on Linux and Clang on MacOS)
45+
- Powershell Core (7 or above)
46+
- A C compiler that support C11 or above (Gcc on Linux, Clang on MacOS and MinGW-x64 on Windows)
4647
- A CMake version of 3.10 or above
4748
- libatomic - which usually come with default Gcc, Clang installation
4849

@@ -56,6 +57,11 @@ This Go Lite version contains only one single package:
5657

5758
## Build and Usage
5859

60+
### Windows
61+
If you are on Windows, make sure the path to the `MinGW-x64` `bin` folder is included in the `PATH`.
62+
63+
### Build steps for all platforms
64+
5965
Currently, it is recommended to build and use `device-detection-go` by cloning the repository rather than installing via `go mod`. To use `device-detection-go` module, users first need to build the core static libraries. There is a powershell script `prebuild.ps1` located in `dd/scripts` folder that assists on building the core static library providing that all pre-requisites have been satisfied. Run the script as below:
6066
```
6167
pwsh -File [path to script]

ci/build-and-test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ stages:
2929
# this is triggered by one.
3030
- template: shared-auto-complete-pr-stage.yml@ciTemplates
3131
parameters:
32-
stageDependencies: [Linux,MacOS]
32+
stageDependencies: [Linux,MacOS,Windows]

ci/shared-build-and-test-stage.yml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,57 @@ stages:
145145
displayName: 'Build device detection core binaries'
146146
workingDirectory: '$(Build.SourcesDirectory)'
147147
148+
# Run test
149+
- task: Go@0
150+
displayName: 'Run tests'
151+
inputs:
152+
command: test
153+
arguments: './...'
154+
155+
# This stage use MinGW-x64 to build binaries.
156+
# By default we only test 64bit version.
157+
- stage: Windows
158+
dependsOn: []
159+
160+
jobs:
161+
- job: Build_and_Test
162+
displayName: Build and Test
163+
condition: ne(${{ parameters.runTests }}, 'Off')
164+
165+
variables:
166+
- group: InternalKeys
167+
168+
strategy:
169+
matrix:
170+
Windows VS 2019:
171+
imageName: 'windows-2019'
172+
173+
pool:
174+
vmImage: $(imageName)
175+
176+
steps:
177+
- checkout: self
178+
submodules: recursive
179+
lfs: true
180+
persistCredentials: true
181+
182+
# Install go
183+
- task: GoTool@0
184+
displayName: 'Use go ${{ parameters.goVersion }}'
185+
inputs:
186+
version: '${{ parameters.goVersion }}'
187+
188+
# Run prebuild
189+
- task: Powershell@2
190+
inputs:
191+
targetType: inline
192+
script: |
193+
$PSVersionTable
194+
./dd/scripts/prebuild.ps1
195+
pwsh: true
196+
displayName: 'Build device detection core binaries'
197+
workingDirectory: '$(Build.SourcesDirectory)'
198+
148199
# Run test
149200
- task: Go@0
150201
displayName: 'Run tests'

dd/constants.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* *********************************************************************
2+
* This Original Work is copyright of 51 Degrees Mobile Experts Limited.
3+
* Copyright 2019 51 Degrees Mobile Experts Limited, 5 Charlotte Close,
4+
* Caversham, Reading, Berkshire, United Kingdom RG4 7BY.
5+
*
6+
* This Original Work is licensed under the European Union Public Licence (EUPL)
7+
* v.1.2 and is subject to its terms as set out below.
8+
*
9+
* If a copy of the EUPL was not distributed with this file, You can obtain
10+
* one at https://opensource.org/licenses/EUPL-1.2.
11+
*
12+
* The 'Compatible Licences' set out in the Appendix to the EUPL (as may be
13+
* amended by the European Commission) shall be deemed incompatible for
14+
* the purposes of the Work and the provisions of the compatibility
15+
* clause in Article 5 of the EUPL shall not apply.
16+
*
17+
* If using the Work as, or as part of, a network application, by
18+
* including the attribution notice(s) required under Article 5 of the EUPL
19+
* in the end user terms of the application under an appropriate heading,
20+
* such notice(s) shall fulfill the requirements of that article.
21+
* ********************************************************************* */
22+
23+
package dd
24+
25+
// Error messages
26+
const (
27+
ErrSHPropertyIncorrectFormat = "'SetHeader' property name is not in correct format."
28+
ErrNoMatch = "No match found."
29+
)

dd/evidence.go

Lines changed: 72 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,47 +25,98 @@ package dd
2525
// #include <string.h>
2626
// #include "./device-detection-cxx/src/common-cxx/fiftyone.h"
2727
import "C"
28+
import (
29+
"runtime"
30+
"unsafe"
31+
)
2832

29-
type EvidencePrefix int
33+
type EvidencePrefix C.fiftyoneDegreesEvidencePrefix
3034

3135
const (
32-
HttpHeaderString EvidencePrefix = 1 << iota
33-
HttpIpAddresses = 1 << iota
34-
HttpEvidenceServer = 1 << iota
35-
HttpEvidenceQuery = 1 << iota
36-
HttpEvidenceCookie = 1 << iota
37-
HttpEvidenceIgnore = 1 << 7
36+
HttpHeaderString EvidencePrefix = C.FIFTYONE_DEGREES_EVIDENCE_HTTP_HEADER_STRING
37+
HttpIpAddresses = C.FIFTYONE_DEGREES_EVIDENCE_HTTP_HEADER_IP_ADDRESSES
38+
HttpEvidenceServer = C.FIFTYONE_DEGREES_EVIDENCE_SERVER
39+
HttpEvidenceQuery = C.FIFTYONE_DEGREES_EVIDENCE_QUERY
40+
HttpEvidenceCookie = C.FIFTYONE_DEGREES_EVIDENCE_COOKIE
41+
HttpEvidenceIgnore = C.FIFTYONE_DEGREES_EVIDENCE_IGNORE
3842
)
3943

44+
// Header Key required by engine
45+
type EvidenceKey struct {
46+
Prefix EvidencePrefix
47+
Key string
48+
}
49+
50+
// C type Evidence
51+
type CEvidence struct {
52+
key *C.char
53+
value *C.char
54+
}
55+
56+
// Evidence structure
4057
type Evidence struct {
41-
CPtr *C.EvidenceKeyValuePairArray
58+
cEvidence []CEvidence
59+
CPtr *C.EvidenceKeyValuePairArray
60+
}
61+
62+
// evidenceFinalizer checks if C resource has been explicitly freed by Free
63+
// method. Panic if it was not.
64+
func evidenceFinalizer(evidence *Evidence) {
65+
if evidence.CPtr != nil {
66+
panic("Error: Evidence should be freed explicitly by its Free method.")
67+
}
4268
}
4369

4470
// NewEvidenceHash returns a new EvidenceHash object with a given capacity
45-
//
46-
// TODO: To be implemeted
47-
func NewEvidenceHash(capacity uint32) (evidence *Evidence, err error) {
48-
// TODO: To be implemented
49-
return nil, nil
71+
func NewEvidenceHash(capacity uint32) (evidence *Evidence) {
72+
cEvidencePtr := C.EvidenceCreate(C.uint32_t(capacity))
73+
e := &Evidence{
74+
make([]CEvidence, 0, capacity),
75+
cEvidencePtr}
76+
runtime.SetFinalizer(e, evidenceFinalizer)
77+
return e
5078
}
5179

5280
// Free frees the evidence resources allocated in the C layer. This matches the
5381
// C API fiftyoneDegreesEvidenceFree
54-
//
55-
// TODO: To be implemeted
56-
func (evidence *Evidence) Free() error {
57-
// TODO: To be implemented
58-
return nil
82+
func (evidence *Evidence) Free() {
83+
// Free the tracked C evidence strings
84+
if evidence.cEvidence != nil {
85+
// Free each cstring in the evidence
86+
for _, e := range evidence.cEvidence {
87+
C.free(unsafe.Pointer(e.key))
88+
C.free(unsafe.Pointer(e.value))
89+
}
90+
evidence.cEvidence = nil
91+
}
92+
93+
// Free the C resources
94+
if evidence.CPtr != nil {
95+
C.EvidenceFree(evidence.CPtr)
96+
evidence.CPtr = nil
97+
}
5998
}
6099

61100
// Add adds a new evidence to the object. This matches the C API
62101
// fiftyoneDegreesEvidenceAddString
63-
//
64-
// TODO: To be implemeted
65102
func (evidence *Evidence) Add(
66103
prefix EvidencePrefix,
67104
key string,
68105
value string) error {
69-
// TODO: To be implemented
106+
cKey := C.CString(key)
107+
cValue := C.CString(value)
108+
// Add it to the tracked map
109+
evidence.cEvidence = append(evidence.cEvidence, CEvidence{cKey, cValue})
110+
C.EvidenceAddString(
111+
evidence.CPtr,
112+
C.fiftyoneDegreesEvidencePrefix(prefix),
113+
cKey,
114+
cValue)
115+
70116
return nil
71117
}
118+
119+
// Count return number of evidence in Evidence object
120+
func (evidence *Evidence) Count() int {
121+
return int(evidence.CPtr.count)
122+
}

dd/evidence_test.go

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/* *********************************************************************
2+
* This Original Work is copyright of 51 Degrees Mobile Experts Limited.
3+
* Copyright 2019 51 Degrees Mobile Experts Limited, 5 Charlotte Close,
4+
* Caversham, Reading, Berkshire, United Kingdom RG4 7BY.
5+
*
6+
* This Original Work is licensed under the European Union Public Licence (EUPL)
7+
* v.1.2 and is subject to its terms as set out below.
8+
*
9+
* If a copy of the EUPL was not distributed with this file, You can obtain
10+
* one at https://opensource.org/licenses/EUPL-1.2.
11+
*
12+
* The 'Compatible Licences' set out in the Appendix to the EUPL (as may be
13+
* amended by the European Commission) shall be deemed incompatible for
14+
* the purposes of the Work and the provisions of the compatibility
15+
* clause in Article 5 of the EUPL shall not apply.
16+
*
17+
* If using the Work as, or as part of, a network application, by
18+
* including the attribution notice(s) required under Article 5 of the EUPL
19+
* in the end user terms of the application under an appropriate heading,
20+
* such notice(s) shall fulfill the requirements of that article.
21+
* ********************************************************************* */
22+
23+
package dd
24+
25+
import "testing"
26+
27+
// Test that NewEvidenceHash create new object with correct capacity.
28+
// Also, test that Free unset everything correctly.
29+
func TestNewEvidenceHash(t *testing.T) {
30+
var capacity uint32 = 10
31+
evidence := NewEvidenceHash(capacity)
32+
if evidence == nil ||
33+
evidence.CPtr == nil ||
34+
evidence.cEvidence == nil ||
35+
uint32(evidence.CPtr.capacity) != capacity {
36+
t.Error("Failed to create new EvidenceHash.")
37+
}
38+
39+
// Free the evidence after created
40+
evidence.Free()
41+
if evidence.CPtr != nil {
42+
t.Error("Failed to set the C pointer to 'nil' after freed.")
43+
}
44+
if evidence.cEvidence != nil {
45+
t.Error("Failed to set tracked C Evidence array to 'nil'.")
46+
}
47+
}
48+
49+
// Test that resource finalizer will panic if a pointer to
50+
// C resource has not been freed
51+
func TestEvidenceFinalizer(t *testing.T) {
52+
evidence := NewEvidenceHash(1)
53+
54+
// Check that panic is thrown and make sure resource
55+
// manager is freed.
56+
defer func() {
57+
if r := recover(); r == nil {
58+
evidence.Free()
59+
t.Error("Evidence finalizer did not panic.")
60+
} else {
61+
evidence.Free()
62+
}
63+
}()
64+
// Perform finalizer on live resource
65+
evidenceFinalizer(evidence)
66+
}
67+
68+
// Test that evidences are added correctly
69+
func TestEvidenceAdd(t *testing.T) {
70+
var capacity uint32 = 10
71+
evidence := NewEvidenceHash(capacity)
72+
73+
// Add new string
74+
testData := []struct {
75+
prefix EvidencePrefix
76+
key string
77+
value string
78+
}{
79+
{HttpHeaderString, "User-Agent-1", "Test User Agent 1"},
80+
{HttpEvidenceCookie, "User-Agent-2", "Test User Agent 2"},
81+
}
82+
83+
// Added evidence
84+
evidence.Add(testData[0].prefix, testData[0].key, testData[0].value)
85+
evidence.Add(testData[1].prefix, testData[1].key, testData[1].value)
86+
87+
// Verify that evidence has been tracked correctly
88+
if len(evidence.cEvidence) != len(testData) {
89+
t.Errorf("Expected '%d' to be added, but actual is '%d'.",
90+
len(testData), len(evidence.cEvidence))
91+
}
92+
93+
// Check the actual count in C resource
94+
if evidence.Count() != len(testData) {
95+
t.Errorf("Expected '%d' to be added, but actual in C resource is '%d'.",
96+
len(testData), len(evidence.cEvidence))
97+
}
98+
99+
// Free the evidence after created
100+
evidence.Free()
101+
if evidence.CPtr != nil {
102+
t.Error("Failed to set the C pointer to 'nil' after freed.")
103+
}
104+
if evidence.cEvidence != nil {
105+
t.Error("Failed to set tracked C Evidence array to 'nil'.")
106+
}
107+
}

0 commit comments

Comments
 (0)